Release: v2.48.0 (#1848)

Co-authored-by: Dariqq <77271900+Dariqq@users.noreply.github.com>
Co-authored-by: Robert Nilson <109800336+ZBookCMD@users.noreply.github.com>
Co-authored-by: Juan Llamas <38849891+xoltia@users.noreply.github.com>
Co-authored-by: Angel Gustavo Lopez <143856402+Xray-OS@users.noreply.github.com>
This commit is contained in:
Carter Li
2025-07-16 15:09:29 +08:00
committed by GitHub
46 changed files with 1081 additions and 298 deletions
+31 -4
View File
@@ -683,7 +683,6 @@ jobs:
haiku-amd64:
name: Haiku-amd64
runs-on: ubuntu-latest
if: false
permissions:
security-events: write
contents: read
@@ -691,17 +690,45 @@ jobs:
- name: checkout repository
uses: actions/checkout@v4
- name: Fixup VM
uses: cross-platform-actions/action@master
with:
operating_system: haiku
version: 'r1beta5'
architecture: x86-64
cpu_count: 4
shell: bash
sync_files: false
shutdown_vm: false
run: |
mv '/home/runner/work' '/boot/home/work'
ln -sf '/boot/home/work' '/home/runner/work'
- name: Sync files to VM
uses: cross-platform-actions/action@master
with:
operating_system: haiku
version: 'r1beta5'
architecture: x86-64
cpu_count: 4
shell: bash
sync_files: runner-to-vm
shutdown_vm: false
run: |
chown -R $(id -u):$(id -g) $(pwd)
ls -l
- name: run VM
uses: cross-platform-actions/action@master
with:
operating_system: haiku
version: 'r1beta5'
architecture: x86-64
cpu_count: 4
shell: bash
version: 'r1beta5'
sync_files: vm-to-runner
run: |
uname -a
ls -l
pkgman install -y git dbus_devel mesa_devel libelf_devel imagemagick_devel opencl_headers ocl_icd_devel vulkan_devel zlib_devel chafa_devel cmake gcc make pkgconfig python3.10
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
cmake --build . --target package --verbose -j4
@@ -709,7 +736,6 @@ jobs:
time ./fastfetch -c presets/ci.jsonc --stat false
time ./fastfetch -c presets/ci.jsonc --format json
time ./flashfetch
ldd fastfetch
ctest --output-on-failure
- name: upload artifacts
@@ -861,6 +887,7 @@ jobs:
- openbsd-amd64
- netbsd-amd64
- sunos-amd64
- haiku-amd64
- windows-amd64
- windows-aarch64
permissions:
+32
View File
@@ -1,3 +1,35 @@
# 2.48.0
Features:
* Add support for detecting Fedora variants (#1830, OS, Linux)
* Currently supported variants: CoreOS, Kinoite, Sericea, Silverblue
* Optimize GPU detection on Windows when `--gpu-driver-specific` is not used (GPU, Windows)
* Improve accuracy of GPU type detection. Previously it was guessed based on the dedicated vmem size, which causes issues on newer AMD integrated GPUs such as 9000 HX and AI 9 HX series. Supported on Windows 8.1 or later.
* Add support for generic frequency detection of GPU 3D engine on Windows 11 22H2 or later.
* Improve performance. GPU temperature detection is significantly improved when `--gpu-driver-specific` is not used.
* Improve performance and security when spawning child processes by replacing `fork-exec` with `posix_spawn` (*nix)
* Improve accuracy of sound device detection on macOS (Sound, macOS)
* Trim leading and trailing whitespaces in disk serial numbers (PhysicalDisk)
* Add `/etc/profiles/per-user` detection for Nix user packages (#1782, Packages, Linux)
* Introduce `years` (whole years as integer), `days-of-year` (days since the last anniversary) and `years-fraction` (years as fraction, e.g. 1.5 means 1 year and 6 months) formatting placeholder to `Disk` (since disk creation), `Users` (since user login) and `Uptime` (since system boot) modules
* For example: `fastfetch -s disk --disk-key 'OS Installation' --disk-format '{years} years {days-of-year} days'`
* Add `--fraction-ndigits` option to specify the number of digits after the decimal point when displaying ordinary fractional values
* Typically used with `{years-fraction}` above
* This option does not affect percentage values, sizes, etc, which are controlled by individual options.
Bugfixes:
* Fix compilation issues when not using `-DBINARY_LINK_TYPE=dlopen`
* Regression from v2.47.0
* Note: this option was added for debugging purposes only and is not recommended for production use
* Replace `MTLDevice::hasUnifiedMemory` with `MTLDevice::location` for GPU type Detection (GPU, macOS)
* This should resolve the issue where discrete GPUs were detected as integrated GPUs on Intel MacBooks with multi-GPU configurations.
* Prevent text files from being loaded as image files (#1843, Logo)
Logos:
* Add Minimal System
* Add AxOS
* Rename Ada to Xray OS
# 2.47.0
Features:
+2 -3
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.47.0
VERSION 2.48.0
LANGUAGES C
DESCRIPTION "Fast neofetch-like system information tool"
HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch"
@@ -336,7 +336,7 @@ endif()
# Ascii image data #
####################
file(GLOB LOGO_FILES "src/logo/ascii/*.txt")
file(GLOB LOGO_FILES CONFIGURE_DEPENDS "src/logo/ascii/*.txt")
set(LOGO_BUILTIN_H "#pragma once\n#pragma GCC diagnostic ignored \"-Wtrigraphs\"\n\n")
foreach(file ${LOGO_FILES})
fastfetch_load_text("${file}" content)
@@ -1582,7 +1582,6 @@ elseif(WIN32)
PRIVATE "ws2_32"
PRIVATE "ntdll"
PRIVATE "version"
PRIVATE "setupapi"
PRIVATE "hid"
PRIVATE "wtsapi32"
PRIVATE "imagehlp"
+2 -1
View File
@@ -10,6 +10,7 @@
[![GitHub release (with filter)](https://img.shields.io/github/v/release/fastfetch-cli/fastfetch?logo=github)](https://github.com/fastfetch-cli/fastfetch/releases)
[![latest packaged version(s)](https://repology.org/badge/latest-versions/fastfetch.svg)](https://repology.org/project/fastfetch/versions)
[![Packaging status](https://repology.org/badge/tiny-repos/fastfetch.svg)](https://repology.org/project/fastfetch/versions)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/fastfetch-cli/fastfetch)
Fastfetch is a [neofetch](https://github.com/dylanaraps/neofetch)-like tool for fetching system information and displaying it in a visually appealing way. It is written mainly in C, with a focus on performance and customizability. Currently, it supports Linux, macOS, Windows 7+, Android, FreeBSD, OpenBSD, NetBSD, DragonFly, Haiku, and SunOS.
@@ -92,7 +93,7 @@ See the Wiki: https://github.com/fastfetch-cli/fastfetch/wiki/Building
* Run with default configuration: `fastfetch`
* Run with [all supported modules](https://github.com/fastfetch-cli/fastfetch/wiki/Support+Status#available-modules) to find what interests you: `fastfetch -c all.jsonc`
* View all data that fastfetch detects: `fastfetch -s <module> --format json`
* View all data that fastfetch detects: `fastfetch -s <module1>[:<module2>][:<module3>] --format json`
* Display help messages: `fastfetch --help`
* Generate a config file based on command line arguments: `fastfetch --arg1 --arg2 --gen-config`
+6
View File
@@ -1,3 +1,9 @@
fastfetch (2.47.0) jammy; urgency=medium
* Update to 2.47.0
-- Carter Li <zhangsongcui@live.cn> Thu, 03 Jul 2025 14:51:45 +0800
fastfetch (2.46.0) jammy; urgency=medium
* Update to 2.46.0
+1 -1
View File
@@ -1 +1 @@
fastfetch_2.46.0_source.buildinfo universe/utils optional
fastfetch_2.47.0_source.buildinfo universe/utils optional
+26 -8
View File
@@ -183,7 +183,7 @@
"type": "string"
},
"diskFormat": {
"description": "Output format of the module `Disk`. See Wiki for formatting syntax\n 1. {size-used}: Size used\n 2. {size-total}: Size total\n 3. {size-percentage}: Size percentage num\n 4. {files-used}: Files used\n 5. {files-total}: Files total\n 6. {files-percentage}: Files percentage num\n 7. {is-external}: True if external volume\n 8. {is-hidden}: True if hidden volume\n 9. {filesystem}: Filesystem\n 10. {name}: Label / name\n 11. {is-readonly}: True if read-only\n 12. {create-time}: Create time in local timezone\n 13. {size-percentage-bar}: Size percentage bar\n 14. {files-percentage-bar}: Files percentage bar\n 15. {days}: Days after creation\n 16. {hours}: Hours after creation\n 17. {minutes}: Minutes after creation\n 18. {seconds}: Seconds after creation\n 19. {milliseconds}: Milliseconds after creation\n 20. {mountpoint}: Mount point / drive letter\n 21. {mount-from}: Mount from (device path)",
"description": "Output format of the module `Disk`. See Wiki for formatting syntax\n 1. {size-used}: Size used\n 2. {size-total}: Size total\n 3. {size-percentage}: Size percentage num\n 4. {files-used}: Files used\n 5. {files-total}: Files total\n 6. {files-percentage}: Files percentage num\n 7. {is-external}: True if external volume\n 8. {is-hidden}: True if hidden volume\n 9. {filesystem}: Filesystem\n 10. {name}: Label / name\n 11. {is-readonly}: True if read-only\n 12. {create-time}: Create time in local timezone\n 13. {size-percentage-bar}: Size percentage bar\n 14. {files-percentage-bar}: Files percentage bar\n 15. {days}: Days after creation\n 16. {hours}: Hours after creation\n 17. {minutes}: Minutes after creation\n 18. {seconds}: Seconds after creation\n 19. {milliseconds}: Milliseconds after creation\n 20. {mountpoint}: Mount point / drive letter\n 21. {mount-from}: Mount from (device path)\n 22. {years}: Years integer after creation\n 23. {days-of-year}: Days of year after creation\n 24. {years-fraction}: Years fraction after creation",
"type": "string"
},
"diskioFormat": {
@@ -306,10 +306,6 @@
"description": "Output format of the module `PublicIp`. See Wiki for formatting syntax\n 1. {ip}: Public IP address\n 2. {location}: Location",
"type": "string"
},
"separatorFormat": {
"description": "Output format of the module `Separator`. See Wiki for formatting syntax\n 1. {string}: Separator string\n 2. {outputColor}: Output color\n 3. {length}: Length",
"type": "string"
},
"shellFormat": {
"description": "Output format of the module `Shell`. See Wiki for formatting syntax\n 1. {process-name}: Shell process name\n 2. {exe}: The first argument of the command line when running the shell\n 3. {exe-name}: Shell base name of arg0\n 4. {version}: Shell version\n 5. {pid}: Shell pid\n 6. {pretty-name}: Shell pretty name\n 7. {exe-path}: Shell full exe path\n 8. {tty}: Shell tty used",
"type": "string"
@@ -319,7 +315,7 @@
"type": "string"
},
"swapFormat": {
"description": "Output format of the module `Swap`. See Wiki for formatting syntax\n 1. {used}: Used size\n 2. {total}: Total size\n 3. {percentage}: Percentage used (num)\n 4. {percentage-bar}: Percentage used (bar)",
"description": "Output format of the module `Swap`. See Wiki for formatting syntax\n 1. {used}: Used size\n 2. {total}: Total size\n 3. {percentage}: Percentage used (num)\n 4. {percentage-bar}: Percentage used (bar)\n 5. {name}: Name",
"type": "string"
},
"terminalFormat": {
@@ -351,11 +347,11 @@
"type": "string"
},
"uptimeFormat": {
"description": "Output format of the module `Uptime`. See Wiki for formatting syntax\n 1. {days}: Days\n 2. {hours}: Hours\n 3. {minutes}: Minutes\n 4. {seconds}: Seconds\n 5. {milliseconds}: Milliseconds\n 6. {boot-time}: Boot time in local timezone",
"description": "Output format of the module `Uptime`. See Wiki for formatting syntax\n 1. {days}: Days after boot\n 2. {hours}: Hours after boot\n 3. {minutes}: Minutes after boot\n 4. {seconds}: Seconds after boot\n 5. {milliseconds}: Milliseconds after boot\n 6. {boot-time}: Boot time in local timezone\n 7. {years}: Years integer after boot\n 8. {days-of-year}: Days of year after boot\n 9. {years-fraction}: Years fraction after boot",
"type": "string"
},
"usersFormat": {
"description": "Output format of the module `Users`. See Wiki for formatting syntax\n 1. {name}: User name\n 2. {host-name}: Host name\n 3. {session}: Session name\n 4. {client-ip}: Client IP\n 5. {login-time}: Login Time in local timezone\n 6. {days}: Days after login\n 7. {hours}: Hours after login\n 8. {minutes}: Minutes after login\n 9. {seconds}: Seconds after login\n 10. {milliseconds}: Milliseconds after login",
"description": "Output format of the module `Users`. See Wiki for formatting syntax\n 1. {name}: User name\n 2. {host-name}: Host name\n 3. {session}: Session name\n 4. {client-ip}: Client IP\n 5. {login-time}: Login Time in local timezone\n 6. {days}: Days after login\n 7. {hours}: Hours after login\n 8. {minutes}: Minutes after login\n 9. {seconds}: Seconds after login\n 10. {milliseconds}: Milliseconds after login\n 11. {years}: Years integer after login\n 12. {days-of-year}: Days of year after login\n 13. {years-fraction}: Years fraction after login",
"type": "string"
},
"versionFormat": {
@@ -934,6 +930,28 @@
}
}
},
"fraction": {
"type": "object",
"additionalProperties": false,
"description": "Set how ordinary fraction numbers should be displayed",
"properties": {
"ndigits": {
"oneOf": [
{
"type": "number",
"description": "Set the number of digits to keep after the decimal point when formatting ordinary fraction numbers",
"minimum": 0,
"maximum": 9
},
{
"type": "null",
"description": "The number of digits will be automatically determined based on the value"
}
],
"default": null
}
}
},
"noBuffer": {
"type": "boolean",
"description": "Whether to disable the stdout application buffer",
+49
View File
@@ -0,0 +1,49 @@
{
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
"logo": {
"type": "small",
"padding": {
"top": 1
}
},
"display": {
"separator": " "
},
"modules": [
"break",
"title",
{
"type": "os",
"key": "os ",
"keyColor": "red"
},
{
"type": "kernel",
"key": "kernel",
"keyColor": "green"
},
{
"type": "host",
"format": "{vendor} {family}",
"key": "host ",
"keyColor": "yellow"
},
{
"type": "packages",
"key": "pkgs ",
"keyColor": "blue"
},
{
"type": "uptime",
"format": "{?days}{days}d {?}{hours}h {minutes}m",
"key": "uptime",
"keyColor": "magenta"
},
{
"type": "memory",
"key": "memory",
"keyColor": "cyan"
},
"break"
]
}
+9 -2
View File
@@ -32,10 +32,16 @@ void ffFormatAppendFormatArg(FFstrbuf* buffer, const FFformatarg* formatarg)
ffStrbufAppend(buffer, (FFstrbuf*)formatarg->value);
break;
case FF_FORMAT_ARG_TYPE_FLOAT:
ffStrbufAppendF(buffer, "%f", *(float*)formatarg->value);
if (instance.config.display.fractionNdigits >= 0)
ffStrbufAppendF(buffer, "%.*f", instance.config.display.fractionNdigits, *(float*)formatarg->value);
else
ffStrbufAppendF(buffer, "%g", *(float*)formatarg->value);
break;
case FF_FORMAT_ARG_TYPE_DOUBLE:
ffStrbufAppendF(buffer, "%g", *(double*)formatarg->value);
if (instance.config.display.fractionNdigits >= 0)
ffStrbufAppendF(buffer, "%.*f", instance.config.display.fractionNdigits, *(double*)formatarg->value);
else
ffStrbufAppendF(buffer, "%g", *(double*)formatarg->value);
break;
case FF_FORMAT_ARG_TYPE_BOOL:
ffStrbufAppendS(buffer, *(bool*)formatarg->value ? "true" : "false");
@@ -108,6 +114,7 @@ static inline bool formatArgSet(const FFformatarg* arg)
{
return arg->value != NULL && (
(arg->type == FF_FORMAT_ARG_TYPE_DOUBLE && *(double*)arg->value > 0.0) || //Also is false for NaN
(arg->type == FF_FORMAT_ARG_TYPE_FLOAT && *(float*)arg->value > 0.0) || //Also is false for NaN
(arg->type == FF_FORMAT_ARG_TYPE_INT && *(int*)arg->value > 0) ||
(arg->type == FF_FORMAT_ARG_TYPE_STRBUF && ((FFstrbuf*)arg->value)->length > 0) ||
(arg->type == FF_FORMAT_ARG_TYPE_STRING && ffStrSet((char*)arg->value)) ||
+1 -1
View File
@@ -74,7 +74,7 @@ void* ffLibraryLoad(const char* path, int maxVersion, ...);
FF_MAYBE_UNUSED void* libraryObjectName = NULL; // Placeholder
#define FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, symbolMapping, symbolName, returnValue) \
symbolMapping = (__typeof__(&symbolName)) &symbolName
symbolMapping = (__typeof__(&symbolName)) &symbolName;
#define FF_LIBRARY_LOAD_SYMBOL(library, symbolName, returnValue) \
FF_MAYBE_UNUSED __typeof__(&symbolName) FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff ## symbolName, symbolName, returnValue);
+1 -1
View File
@@ -7,7 +7,7 @@
#include "util/debug.h"
#include <unistd.h>
#include <sys/poll.h>
#include <poll.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netdb.h>
+77 -25
View File
@@ -11,6 +11,7 @@
#include <fcntl.h>
#include <errno.h>
#include <sys/wait.h>
#include <spawn.h>
#if defined(__FreeBSD__) || defined(__APPLE__)
#include <sys/types.h>
@@ -33,6 +34,10 @@
#include <image.h>
#endif
#ifndef environ
extern char** environ;
#endif
enum { FF_PIPE_BUFSIZ = 8192 };
static inline int ffPipe2(int* fds, int flags)
@@ -48,6 +53,8 @@ static inline int ffPipe2(int* fds, int flags)
#endif
}
// Not thread-safe
const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool useStdErr)
{
int pipes[2];
@@ -56,28 +63,63 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
if(ffPipe2(pipes, O_CLOEXEC) == -1)
return "pipe() failed";
pid_t childPid = fork();
if(childPid == -1)
posix_spawn_file_actions_t file_actions;
posix_spawn_file_actions_init(&file_actions);
posix_spawn_file_actions_adddup2(&file_actions, pipes[1], useStdErr ? STDERR_FILENO : STDOUT_FILENO);
posix_spawn_file_actions_addopen(&file_actions, useStdErr ? STDOUT_FILENO : STDERR_FILENO, "/dev/null", O_WRONLY, 0);
pid_t childPid = -1;
static char* oldLang = NULL;
static int langIndex = -1;
if (langIndex >= 0)
{
// Found before
if (oldLang) // oldLang was set only if it needed to be changed
{
if (environ[langIndex] != oldLang)
{
// environ is changed outside of this function
langIndex = -1;
}
else
environ[langIndex] = (char*) "LANG=C.UTF-8";
}
}
if (langIndex < 0)
{
for (int i = 0; environ[i] != NULL; i++)
{
if (ffStrStartsWith(environ[i], "LANG="))
{
langIndex = i;
const char* langValue = environ[i] + 5; // Skip "LANG="
if (ffStrEqualsIgnCase(langValue, "C") ||
ffStrStartsWithIgnCase(environ[i], "C.") ||
ffStrEqualsIgnCase(langValue, "en_US") ||
ffStrStartsWithIgnCase(langValue, "en_US."))
break; // No need to change LANG
oldLang = environ[i];
environ[i] = (char*) "LANG=C.UTF-8"; // Set LANG to C.UTF-8 for consistent output
break;
}
}
}
int ret = posix_spawnp(&childPid, argv[0], &file_actions, NULL, argv, environ);
if (oldLang)
environ[langIndex] = oldLang;
posix_spawn_file_actions_destroy(&file_actions);
close(pipes[1]);
if (ret != 0)
{
close(pipes[0]);
close(pipes[1]);
return "fork() failed";
return "posix_spawnp() failed";
}
//Child
if(childPid == 0)
{
int nullFile = open("/dev/null", O_WRONLY | O_CLOEXEC);
dup2(pipes[1], useStdErr ? STDERR_FILENO : STDOUT_FILENO);
dup2(nullFile, useStdErr ? STDOUT_FILENO : STDERR_FILENO);
setenv("LANG", "C", 1);
execvp(argv[0], argv);
_exit(127);
}
//Parent
close(pipes[1]);
int FF_AUTO_CLOSE_FD childPipeFd = pipes[0];
char str[FF_PIPE_BUFSIZ];
@@ -86,20 +128,30 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
if (timeout >= 0)
{
struct pollfd pollfd = { childPipeFd, POLLIN, 0 };
if (poll(&pollfd, 1, timeout) == 0)
int pollret = poll(&pollfd, 1, timeout);
if (pollret == 0)
{
kill(childPid, SIGTERM);
waitpid(childPid, NULL, 0);
return "poll(&pollfd, 1, timeout) timeout (try increasing --processing-timeout)";
}
else if (errno == EINTR)
else if (pollret < 0)
{
// The child process has been terminated. See `chldSignalHandler` in `common/init.c`
if (waitpid(childPid, NULL, WNOHANG) == childPid)
if (errno == EINTR)
{
// Read remaining data from the pipe
fcntl(childPipeFd, F_SETFL, O_CLOEXEC | O_NONBLOCK);
childPid = -1;
// The child process has been terminated. See `chldSignalHandler` in `common/init.c`
if (waitpid(childPid, NULL, WNOHANG) == childPid)
{
// Read remaining data from the pipe
fcntl(childPipeFd, F_SETFL, O_CLOEXEC | O_NONBLOCK);
childPid = -1;
}
}
else
{
kill(childPid, SIGTERM);
waitpid(childPid, NULL, 0);
return "poll(&pollfd, 1, timeout) error";
}
}
else if (pollfd.revents & POLLERR)
+44
View File
@@ -97,3 +97,47 @@ static inline const char* ffTimeToTimeStr(uint64_t msec)
#ifdef _WIN32
#pragma GCC diagnostic pop
#endif
typedef struct FFTimeGetAgeResult
{
uint32_t years;
uint32_t daysOfYear;
double yearsFraction;
} FFTimeGetAgeResult;
static inline FFTimeGetAgeResult ffTimeGetAge(uint64_t birthMs, uint64_t nowMs)
{
FFTimeGetAgeResult result = {};
if (__builtin_expect(birthMs == 0 || nowMs < birthMs, 0))
return result;
time_t birth_s = (time_t) (birthMs / 1000);
struct tm birth_tm;
#ifdef _WIN32
localtime_s(&birth_tm, &birth_s);
#else
localtime_r(&birth_s, &birth_tm);
#endif
time_t now_s = (time_t) (nowMs / 1000);
struct tm now_tm;
#ifdef _WIN32
localtime_s(&now_tm, &now_s);
#else
localtime_r(&now_s, &now_tm);
#endif
result.years = (uint32_t) (now_tm.tm_year - birth_tm.tm_year);
if (now_tm.tm_yday < birth_tm.tm_yday)
result.years--;
birth_tm.tm_year += result.years;
birth_s = mktime(&birth_tm);
uint32_t diff_s = (uint32_t) (now_s - birth_s);
result.daysOfYear = diff_s / (24 * 60 * 60);
birth_tm.tm_year += 1;
result.yearsFraction = (double) diff_s / (double) (mktime(&birth_tm) - birth_s) + result.years;
return result;
}
+9
View File
@@ -719,6 +719,15 @@
"default": 2
}
},
{
"long": "fraction-ndigits",
"desc": "Set the number of digits to keep after the decimal point when printing ordinary fraction numbers",
"remark": "If negative, the number of digits will be automatically determined based on the value",
"arg": {
"type": "num",
"default": -1
}
},
{
"long": "temp-unit",
"desc": "Set the temperature unit",
+19 -28
View File
@@ -8,40 +8,31 @@
#undef WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <setupapi.h>
#include <batclass.h>
#include <devguid.h>
#include <cfgmgr32.h>
#include <winternl.h>
static inline void wrapSetupDiDestroyDeviceInfoList(HDEVINFO* hdev)
static const char* detectWithCmApi(FFBatteryOptions* options, FFlist* results)
{
if(*hdev)
SetupDiDestroyDeviceInfoList(*hdev);
}
//https://learn.microsoft.com/en-us/windows-hardware/drivers/install/using-device-interfaces
ULONG cchDeviceInterfaces = 0;
CONFIGRET cr = CM_Get_Device_Interface_List_SizeW(&cchDeviceInterfaces, (LPGUID)&GUID_DEVCLASS_BATTERY, NULL, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
if (cr != CR_SUCCESS)
return "CM_Get_Device_Interface_List_SizeW() failed";
static const char* detectWithSetupApi(FFBatteryOptions* options, FFlist* results)
{
//https://learn.microsoft.com/en-us/windows/win32/power/enumerating-battery-devices
HDEVINFO hdev __attribute__((__cleanup__(wrapSetupDiDestroyDeviceInfoList))) =
SetupDiGetClassDevsW(&GUID_DEVCLASS_BATTERY, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if(hdev == INVALID_HANDLE_VALUE)
return "SetupDiGetClassDevsW(&GUID_DEVCLASS_BATTERY) failed";
if (cchDeviceInterfaces <= 1)
return NULL; // Not found
SP_DEVICE_INTERFACE_DATA did = { .cbSize = sizeof(did) };
for(DWORD idev = 0; SetupDiEnumDeviceInterfaces(hdev, NULL, &GUID_DEVCLASS_BATTERY, idev, &did); idev++)
wchar_t* FF_AUTO_FREE mszDeviceInterfaces = (wchar_t*)malloc(cchDeviceInterfaces * sizeof(wchar_t));
cr = CM_Get_Device_Interface_ListW((LPGUID)&GUID_DEVCLASS_BATTERY, NULL, mszDeviceInterfaces, cchDeviceInterfaces, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
if (cr != CR_SUCCESS)
return "CM_Get_Device_Interface_ListW() failed";
for (const wchar_t* pDeviceInterface = mszDeviceInterfaces; *pDeviceInterface; pDeviceInterface += wcslen(pDeviceInterface) + 1)
{
DWORD cbRequired = 0;
SetupDiGetDeviceInterfaceDetailW(hdev, &did, NULL, 0, &cbRequired, NULL); //Fail with not enough buffer
SP_DEVICE_INTERFACE_DETAIL_DATA_W* FF_AUTO_FREE pdidd = (SP_DEVICE_INTERFACE_DETAIL_DATA_W*)malloc(cbRequired);
if(!pdidd)
break; //Out of memory
pdidd->cbSize = sizeof(*pdidd);
if(!SetupDiGetDeviceInterfaceDetailW(hdev, &did, pdidd, cbRequired, &cbRequired, NULL))
continue;
HANDLE FF_AUTO_CLOSE_FD hBattery =
CreateFileW(pdidd->DevicePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
CreateFileW(pDeviceInterface, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(hBattery == INVALID_HANDLE_VALUE)
continue;
@@ -99,7 +90,7 @@ static const char* detectWithSetupApi(FFBatteryOptions* options, FFlist* results
bqi.InformationLevel = BatteryManufactureDate;
BATTERY_MANUFACTURE_DATE date;
if(DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), &date, sizeof(date), &dwOut, NULL))
ffStrbufSetF(&battery->manufactureDate, "%.4d-%.2d-%.2d", date.Year + 1900, date.Month, date.Day);
ffStrbufSetF(&battery->manufactureDate, "%.4d-%.2d-%.2d", date.Year < 1000 ? date.Year + 1900 : date.Year, date.Month, date.Day);
}
{
@@ -131,7 +122,7 @@ static const char* detectWithSetupApi(FFBatteryOptions* options, FFlist* results
{
BATTERY_STATUS bs;
BATTERY_WAIT_STATUS bws = { .BatteryTag = bqi.BatteryTag };
if(DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_STATUS, &bws, sizeof(bws), &bs, sizeof(bs), &dwOut, NULL) && bs.Capacity != BATTERY_UNKNOWN_CAPACITY)
if(DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_STATUS, &bws, sizeof(bws), &bs, sizeof(bs), &dwOut, NULL) && bs.Capacity != BATTERY_UNKNOWN_CAPACITY && bi.FullChargedCapacity != 0)
battery->capacity = bs.Capacity * 100.0 / bi.FullChargedCapacity;
else
battery->capacity = 0;
@@ -271,6 +262,6 @@ static const char* detectWithNtApi(FF_MAYBE_UNUSED FFBatteryOptions* options, FF
const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results)
{
return options->useSetupApi
? detectWithSetupApi(options, results)
? detectWithCmApi(options, results)
: detectWithNtApi(options, results);
}
+1 -1
View File
@@ -283,7 +283,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
while((device = getmntent(mountsFile)))
{
if (__builtin_expect(options->folders.length, 0))
if (__builtin_expect(options->folders.length > 0, false))
{
if (!ffDiskMatchMountpoint(&options->folders, device->mnt_dir))
continue;
+1 -1
View File
@@ -71,7 +71,7 @@ const char* ffGpuDetectMetal(FFlist* gpus)
else if ([device supportsFamily:MTLGPUFamilyCommon1])
ffStrbufSetStatic(&gpu->platformApi, "Metal Common 1");
gpu->type = device.location == MTLDeviceLocationBuiltIn ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
gpu->type = device.hasUnifiedMemory ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
gpu->index = (uint32_t) device.locationNumber;
if (device.hasUnifiedMemory && device.recommendedMaxWorkingSetSize > 0)
+1 -1
View File
@@ -305,7 +305,7 @@ const char* ffDrmDetectAsahi(FFGPUResult* gpu, int fd)
struct drm_asahi_params_global paramsGlobal = {};
if (ioctl(fd, DRM_IOCTL_ASAHI_GET_PARAMS, &(struct drm_asahi_get_params) {
.param_group = DRM_ASAHI_GET_PARAMS,
.pointer = (uint64_t) &paramsGlobal,
.pointer = (uintptr_t) &paramsGlobal,
.size = sizeof(paramsGlobal),
}) >= 0)
{
+6 -6
View File
@@ -89,19 +89,19 @@ const char* ffDetectIntelGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverRe
if (properties.device_type != CTL_DEVICE_TYPE_GRAPHICS)
continue;
if (cond->type & FF_GPU_DRIVER_CONDITION_TYPE_LUID)
if (cond->type & FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID)
{
if (cond->luid == deviceId)
if (cond->pciBusId.bus == properties.adapter_bdf.bus &&
cond->pciBusId.device == properties.adapter_bdf.device &&
cond->pciBusId.func == properties.adapter_bdf.function)
{
device = devices[iDev];
break;
}
}
else if (cond->type & FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID)
else if (cond->type & FF_GPU_DRIVER_CONDITION_TYPE_LUID)
{
if (cond->pciBusId.bus == properties.adapter_bdf.bus &&
cond->pciBusId.device == properties.adapter_bdf.device &&
cond->pciBusId.func == properties.adapter_bdf.function)
if (cond->luid == deviceId)
{
device = devices[iDev];
break;
+51 -31
View File
@@ -29,11 +29,12 @@ struct FFNvapiData {
FF_LIBRARY_SYMBOL(nvapi_Unload)
FF_LIBRARY_SYMBOL(nvapi_EnumPhysicalGPUs)
FF_LIBRARY_SYMBOL(nvapi_GPU_GetRamType)
FF_LIBRARY_SYMBOL(nvapi_GPU_GetGPUType)
bool inited;
} nvapiData;
static const char* detectMemTypeByNvapi(FFGpuDriverResult* result)
static const char* detectMoreByNvapi(FFGpuDriverResult* result)
{
if (!nvapiData.inited)
{
@@ -55,6 +56,7 @@ static const char* detectMemTypeByNvapi(FFGpuDriverResult* result)
FF_NVAPI_INTERFACE(nvapi_Unload, NVAPI_INTERFACE_OFFSET_UNLOAD)
FF_NVAPI_INTERFACE(nvapi_EnumPhysicalGPUs, NVAPI_INTERFACE_OFFSET_ENUM_PHYSICAL_GPUS)
FF_NVAPI_INTERFACE(nvapi_GPU_GetRamType, NVAPI_INTERFACE_OFFSET_GPU_GET_RAM_TYPE)
FF_NVAPI_INTERFACE(nvapi_GPU_GetGPUType, NVAPI_INTERFACE_OFFSET_GPU_GET_GPU_TYPE)
#undef FF_NVAPI_INTERFACE
if (ffnvapi_Initialize() < 0)
@@ -62,6 +64,7 @@ static const char* detectMemTypeByNvapi(FFGpuDriverResult* result)
nvapiData.ffnvapi_EnumPhysicalGPUs = ffnvapi_EnumPhysicalGPUs;
nvapiData.ffnvapi_GPU_GetRamType = ffnvapi_GPU_GetRamType;
nvapiData.ffnvapi_GPU_GetGPUType = ffnvapi_GPU_GetGPUType;
nvapiData.ffnvapi_Unload = ffnvapi_Unload;
atexit((void*) ffnvapi_Unload);
@@ -86,36 +89,53 @@ static const char* detectMemTypeByNvapi(FFGpuDriverResult* result)
NvPhysicalGpuHandle gpuHandle = handles[gpuIndex];
NvApiGPUMemoryType memType;
if (nvapiData.ffnvapi_GPU_GetRamType(gpuHandle, &memType) < 0)
return "NvAPI_GPU_GetRamType() failed";
switch (memType)
if (result->memoryType && nvapiData.ffnvapi_GPU_GetRamType(gpuHandle, &memType) == 0)
{
#define FF_NVAPI_MEMORY_TYPE(type) \
case NVAPI_GPU_MEMORY_TYPE_##type: \
ffStrbufSetStatic(result->memoryType, #type); \
switch (memType)
{
#define FF_NVAPI_MEMORY_TYPE(type) \
case NVAPI_GPU_MEMORY_TYPE_##type: \
ffStrbufSetStatic(result->memoryType, #type); \
break;
FF_NVAPI_MEMORY_TYPE(UNKNOWN)
FF_NVAPI_MEMORY_TYPE(SDRAM)
FF_NVAPI_MEMORY_TYPE(DDR1)
FF_NVAPI_MEMORY_TYPE(DDR2)
FF_NVAPI_MEMORY_TYPE(GDDR2)
FF_NVAPI_MEMORY_TYPE(GDDR3)
FF_NVAPI_MEMORY_TYPE(GDDR4)
FF_NVAPI_MEMORY_TYPE(DDR3)
FF_NVAPI_MEMORY_TYPE(GDDR5)
FF_NVAPI_MEMORY_TYPE(LPDDR2)
FF_NVAPI_MEMORY_TYPE(GDDR5X)
FF_NVAPI_MEMORY_TYPE(LPDDR3)
FF_NVAPI_MEMORY_TYPE(LPDDR4)
FF_NVAPI_MEMORY_TYPE(LPDDR5)
FF_NVAPI_MEMORY_TYPE(GDDR6)
FF_NVAPI_MEMORY_TYPE(GDDR6X)
FF_NVAPI_MEMORY_TYPE(GDDR7)
#undef FF_NVAPI_MEMORY_TYPE
default:
ffStrbufSetF(result->memoryType, "Unknown (%d)", memType);
break;
FF_NVAPI_MEMORY_TYPE(UNKNOWN)
FF_NVAPI_MEMORY_TYPE(SDRAM)
FF_NVAPI_MEMORY_TYPE(DDR1)
FF_NVAPI_MEMORY_TYPE(DDR2)
FF_NVAPI_MEMORY_TYPE(GDDR2)
FF_NVAPI_MEMORY_TYPE(GDDR3)
FF_NVAPI_MEMORY_TYPE(GDDR4)
FF_NVAPI_MEMORY_TYPE(DDR3)
FF_NVAPI_MEMORY_TYPE(GDDR5)
FF_NVAPI_MEMORY_TYPE(LPDDR2)
FF_NVAPI_MEMORY_TYPE(GDDR5X)
FF_NVAPI_MEMORY_TYPE(LPDDR3)
FF_NVAPI_MEMORY_TYPE(LPDDR4)
FF_NVAPI_MEMORY_TYPE(LPDDR5)
FF_NVAPI_MEMORY_TYPE(GDDR6)
FF_NVAPI_MEMORY_TYPE(GDDR6X)
FF_NVAPI_MEMORY_TYPE(GDDR7)
#undef FF_NVAPI_MEMORY_TYPE
default:
ffStrbufSetF(result->memoryType, "Unknown (%d)", memType);
break;
}
}
NvApiGPUType gpuType;
if (result->type && nvapiData.ffnvapi_GPU_GetGPUType(gpuHandle, &gpuType) == 0)
{
switch (gpuType)
{
case NV_SYSTEM_TYPE_IGPU:
*result->type = FF_GPU_TYPE_INTEGRATED;
break;
case NV_SYSTEM_TYPE_DGPU:
*result->type = FF_GPU_TYPE_DISCRETE;
break;
default:
*result->type = FF_GPU_TYPE_UNKNOWN;
break;
}
}
return NULL;
@@ -222,13 +242,13 @@ const char* ffDetectNvidiaGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverR
{
*result.index = value;
#ifdef _WIN32
// Don't bother loading nvapi for GPU type detection only
if (result.memoryType)
detectMemTypeByNvapi(&result);
detectMoreByNvapi(&result);
#endif
}
}
if (result.temp)
{
uint32_t value;
+193 -84
View File
@@ -1,18 +1,15 @@
#include "gpu.h"
#include "common/library.h"
#include "detection/gpu/gpu_driver_specific.h"
#include "util/windows/unicode.h"
#include "util/windows/registry.h"
#include "util/mallocHelper.h"
#define INITGUID
#include <windows.h>
#include <setupapi.h>
#include <devguid.h>
static inline void wrapSetupDiDestroyDeviceInfoList(HDEVINFO* hdev)
{
if(*hdev)
SetupDiDestroyDeviceInfoList(*hdev);
}
#include <cfgmgr32.h>
#include <ntddvdeo.h>
#include <devpkey.h>
#include "util/windows/nt.h"
#define FF_EMPTY_GUID_STR L"{00000000-0000-0000-0000-000000000000}"
enum { FF_GUID_STRLEN = sizeof(FF_EMPTY_GUID_STR) / sizeof(wchar_t) - 1 };
@@ -24,21 +21,38 @@ const uint32_t regDriverKeyPrefixLength = (uint32_t) __builtin_strlen("SYSTEM\\C
const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpus)
{
HDEVINFO hdev __attribute__((__cleanup__(wrapSetupDiDestroyDeviceInfoList))) =
SetupDiGetClassDevsW(&GUID_DEVCLASS_DISPLAY, NULL, NULL, DIGCF_PRESENT);
ULONG devInfListSize = 0;
if (CM_Get_Device_Interface_List_SizeW(&devInfListSize, (LPGUID)&GUID_DEVINTERFACE_DISPLAY_ADAPTER, NULL, CM_GET_DEVICE_INTERFACE_LIST_PRESENT) != CR_SUCCESS || devInfListSize <= 1)
return "No display devices found";
if(hdev == INVALID_HANDLE_VALUE)
return "SetupDiGetClassDevsW(&GUID_DEVCLASS_DISPLAY) failed";
FF_AUTO_FREE DEVINSTID_W devInfList = malloc(devInfListSize * sizeof(*devInfList));
SP_DEVINFO_DATA did = { .cbSize = sizeof(did) };
for (DWORD idev = 0; SetupDiEnumDeviceInfo(hdev, idev, &did); ++idev)
if (CM_Get_Device_Interface_ListW((LPGUID)&GUID_DEVINTERFACE_DISPLAY_ADAPTER, NULL, devInfList, devInfListSize, CM_GET_DEVICE_INTERFACE_LIST_PRESENT) != CR_SUCCESS)
return "CM_Get_Device_Interface_ListW failed";
for (wchar_t* devInf = devInfList; *devInf; devInf += wcslen(devInf) + 1)
{
if (wcsncmp(devInf, L"\\\\?\\ROOT#BasicDisplay#", 22) == 0)
continue; // Skip Microsoft Basic Display Adapter
DEVINST devInst = 0;
wchar_t buffer[256];
ULONG bufferLen = 0;
{
DEVPROPTYPE propertyType;
bufferLen = sizeof(buffer);
if (CM_Get_Device_Interface_PropertyW(devInf, &DEVPKEY_Device_InstanceId, &propertyType, (PBYTE) buffer, &bufferLen, 0) != CR_SUCCESS ||
CM_Locate_DevNodeW(&devInst, buffer, CM_LOCATE_DEVNODE_NORMAL) != CR_SUCCESS)
continue;
}
FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus);
ffStrbufInit(&gpu->vendor);
ffStrbufInit(&gpu->name);
ffStrbufInit(&gpu->driver);
ffStrbufInit(&gpu->memoryType);
ffStrbufInitStatic(&gpu->platformApi, "SetupAPI");
ffStrbufInitStatic(&gpu->platformApi, "CM API");
gpu->index = FF_GPU_INDEX_UNSET;
gpu->temperature = FF_GPU_TEMP_UNSET;
gpu->coreCount = FF_GPU_CORE_COUNT_UNSET;
@@ -48,86 +62,91 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
gpu->deviceId = 0;
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
uint32_t pciBus = 0, pciAddr = 0, pciDev = 0, pciFunc = 0;
if (SetupDiGetDeviceRegistryPropertyW(hdev, &did, SPDRP_BUSNUMBER, NULL, (PBYTE) &pciBus, sizeof(pciBus), NULL) &&
SetupDiGetDeviceRegistryPropertyW(hdev, &did, SPDRP_ADDRESS, NULL, (PBYTE) &pciAddr, sizeof(pciAddr), NULL))
{
pciDev = (pciAddr >> 16) & 0xFFFF;
pciFunc = pciAddr & 0xFFFF;
gpu->deviceId = (pciBus * 1000ull) + (pciDev * 10ull) + pciFunc;
pciAddr = 1; // Set to 1 to indicate that the device is a PCI device
}
unsigned vendorId = 0, deviceId = 0, subSystemId = 0, revId = 0;
if (swscanf(buffer, L"PCI\\VEN_%x&DEV_%x&SUBSYS_%x&REV_%x", &vendorId, &deviceId, &subSystemId, &revId) == 4)
ffStrbufSetStatic(&gpu->vendor, ffGPUGetVendorString(vendorId));
wchar_t buffer[256];
uint32_t pciBus = 0, pciAddr = 0, pciDev = 0, pciFunc = 0;
ULONG pciBufLen = sizeof(pciBus);
if (CM_Get_DevNode_Registry_PropertyW(devInst, CM_DRP_BUSNUMBER, NULL, &pciBus, &pciBufLen, 0) == CR_SUCCESS)
{
pciBufLen = sizeof(pciAddr);
if (CM_Get_DevNode_Registry_PropertyW(devInst, CM_DRP_ADDRESS, NULL, &pciAddr, &pciBufLen, 0) == CR_SUCCESS)
{
pciDev = (pciAddr >> 16) & 0xFFFF;
pciFunc = pciAddr & 0xFFFF;
gpu->deviceId = (pciBus * 1000ull) + (pciDev * 10ull) + pciFunc;
pciAddr = 1; // Set to 1 to indicate that the device is a PCI device
}
}
uint64_t adapterLuid = 0;
FF_HKEY_AUTO_DESTROY hVideoIdKey = SetupDiOpenDevRegKey(hdev, &did, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE);
if (!hVideoIdKey) continue;
DWORD bufferLen = sizeof(buffer);
if (RegGetValueW(hVideoIdKey, NULL, L"VideoID", RRF_RT_REG_SZ, NULL, buffer, &bufferLen) == ERROR_SUCCESS &&
bufferLen == (FF_GUID_STRLEN + 1) * sizeof(wchar_t))
FF_HKEY_AUTO_DESTROY hVideoIdKey = NULL;
if (CM_Open_DevNode_Key(devInst, KEY_QUERY_VALUE, 0, RegDisposition_OpenExisting, &hVideoIdKey, CM_REGISTRY_HARDWARE) == CR_SUCCESS)
{
wmemcpy(regDirectxKey + regDirectxKeyPrefixLength, buffer, FF_GUID_STRLEN);
FF_HKEY_AUTO_DESTROY hDirectxKey = NULL;
if (ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, regDirectxKey, &hDirectxKey, NULL))
bufferLen = sizeof(buffer);
if (RegGetValueW(hVideoIdKey, NULL, L"VideoID", RRF_RT_REG_SZ, NULL, buffer, &bufferLen) == ERROR_SUCCESS &&
bufferLen == (FF_GUID_STRLEN + 1) * sizeof(wchar_t))
{
uint32_t vendorId = 0;
if(ffRegReadUint(hDirectxKey, L"VendorId", &vendorId, NULL) && vendorId)
ffStrbufSetStatic(&gpu->vendor, ffGPUGetVendorString(vendorId));
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL)
gpu->type = gpu->deviceId == 20 ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
uint64_t dedicatedVideoMemory = 0;
if(ffRegReadUint64(hDirectxKey, L"DedicatedVideoMemory", &dedicatedVideoMemory, NULL))
wmemcpy(regDirectxKey + regDirectxKeyPrefixLength, buffer, FF_GUID_STRLEN);
FF_HKEY_AUTO_DESTROY hDirectxKey = NULL;
if (ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, regDirectxKey, &hDirectxKey, NULL))
{
if (gpu->type == FF_GPU_TYPE_UNKNOWN)
gpu->type = dedicatedVideoMemory >= 1024 * 1024 * 1024 ? FF_GPU_TYPE_DISCRETE : FF_GPU_TYPE_INTEGRATED;
}
if (gpu->vendor.length == 0)
{
uint32_t vendorId = 0;
if(ffRegReadUint(hDirectxKey, L"VendorId", &vendorId, NULL) && vendorId)
ffStrbufSetStatic(&gpu->vendor, ffGPUGetVendorString(vendorId));
}
uint64_t dedicatedSystemMemory, sharedSystemMemory;
if(ffRegReadUint64(hDirectxKey, L"DedicatedSystemMemory", &dedicatedSystemMemory, NULL) &&
ffRegReadUint64(hDirectxKey, L"SharedSystemMemory", &sharedSystemMemory, NULL))
{
gpu->dedicated.total = dedicatedVideoMemory + dedicatedSystemMemory;
gpu->shared.total = sharedSystemMemory;
}
ffRegReadStrbuf(hDirectxKey, L"Description", &gpu->name, NULL);
if (ffRegReadUint64(hDirectxKey, L"AdapterLuid", &adapterLuid, NULL))
{
if (!gpu->deviceId) gpu->deviceId = adapterLuid;
}
ffRegReadUint64(hDirectxKey, L"DedicatedVideoMemory", &gpu->dedicated.total, NULL);
if (ffRegReadUint64(hDirectxKey, L"DedicatedSystemMemory", &gpu->shared.total, NULL))
{
uint64_t sharedSystemMemory = 0;
if (ffRegReadUint64(hDirectxKey, L"SharedSystemMemory", &sharedSystemMemory, NULL))
gpu->shared.total += sharedSystemMemory;
}
uint32_t featureLevel = 0;
if(ffRegReadUint(hDirectxKey, L"MaxD3D12FeatureLevel", &featureLevel, NULL) && featureLevel)
ffStrbufSetF(&gpu->platformApi, "Direct3D 12.%u", (featureLevel & 0x0F00) >> 8);
else if(ffRegReadUint(hDirectxKey, L"MaxD3D11FeatureLevel", &featureLevel, NULL) && featureLevel)
ffStrbufSetF(&gpu->platformApi, "Direct3D 11.%u", (featureLevel & 0x0F00) >> 8);
if (ffRegReadUint64(hDirectxKey, L"AdapterLuid", &adapterLuid, NULL))
{
if (!gpu->deviceId) gpu->deviceId = adapterLuid;
}
uint64_t driverVersion = 0;
if(ffRegReadUint64(hDirectxKey, L"DriverVersion", &driverVersion, NULL) && driverVersion)
{
ffStrbufSetF(&gpu->driver, "%u.%u.%u.%u",
(unsigned) (driverVersion >> 48) & 0xFFFF,
(unsigned) (driverVersion >> 32) & 0xFFFF,
(unsigned) (driverVersion >> 16) & 0xFFFF,
(unsigned) (driverVersion >> 0) & 0xFFFF
);
uint32_t featureLevel = 0;
if(ffRegReadUint(hDirectxKey, L"MaxD3D12FeatureLevel", &featureLevel, NULL) && featureLevel)
ffStrbufSetF(&gpu->platformApi, "Direct3D 12.%u", (featureLevel & 0x0F00) >> 8);
else if(ffRegReadUint(hDirectxKey, L"MaxD3D11FeatureLevel", &featureLevel, NULL) && featureLevel)
ffStrbufSetF(&gpu->platformApi, "Direct3D 11.%u", (featureLevel & 0x0F00) >> 8);
uint64_t driverVersion = 0;
if(ffRegReadUint64(hDirectxKey, L"DriverVersion", &driverVersion, NULL) && driverVersion)
{
ffStrbufSetF(&gpu->driver, "%u.%u.%u.%u",
(unsigned) (driverVersion >> 48) & 0xFFFF,
(unsigned) (driverVersion >> 32) & 0xFFFF,
(unsigned) (driverVersion >> 16) & 0xFFFF,
(unsigned) (driverVersion >> 0) & 0xFFFF
);
}
}
}
}
if (gpu->vendor.length == 0)
if (gpu->vendor.length == 0 || gpu->name.length == 0)
{
bufferLen = sizeof(buffer);
if (SetupDiGetDeviceRegistryPropertyW(hdev, &did, SPDRP_DRIVER, NULL, (PBYTE) buffer, sizeof(buffer), &bufferLen) && bufferLen == (FF_GUID_STRLEN + strlen("\\0000") + 1) * 2)
if (CM_Get_DevNode_Registry_PropertyW(devInst, CM_DRP_DRIVER, NULL, buffer, &bufferLen, 0) == CR_SUCCESS &&
bufferLen == (FF_GUID_STRLEN + strlen("\\0000") + 1) * 2)
{
wmemcpy(regDriverKey + regDriverKeyPrefixLength, buffer, FF_GUID_STRLEN + strlen("\\0000"));
FF_HKEY_AUTO_DESTROY hRegDriverKey = NULL;
if (ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, regDriverKey, &hRegDriverKey, NULL))
{
if (ffRegReadStrbuf(hRegDriverKey, L"ProviderName", &gpu->vendor, NULL))
if (gpu->vendor.length == 0 && ffRegReadStrbuf(hRegDriverKey, L"ProviderName", &gpu->vendor, NULL))
{
if (ffStrbufContainS(&gpu->vendor, "Intel"))
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_INTEL);
@@ -136,6 +155,19 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
else if (ffStrbufContainS(&gpu->vendor, "AMD") || ffStrbufContainS(&gpu->vendor, "ATI"))
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_AMD);
}
if (gpu->name.length == 0)
ffRegReadStrbuf(hRegDriverKey, L"DriverDesc", &gpu->name, NULL);
if (gpu->driver.length == 0)
ffRegReadStrbuf(hRegDriverKey, L"DriverVersion", &gpu->driver, NULL);
if (gpu->dedicated.total == FF_GPU_VMEM_SIZE_UNSET)
{
if (!ffRegReadUint64(hRegDriverKey, L"HardwareInformation.qwMemorySize", &gpu->dedicated.total, NULL))
{
uint32_t memorySize = 0;
if (ffRegReadUint(hRegDriverKey, L"HardwareInformation.MemorySize", &memorySize, NULL))
gpu->dedicated.total = memorySize;
}
}
}
}
}
@@ -143,18 +175,11 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
__typeof__(&ffDetectNvidiaGpuInfo) detectFn;
const char* dllName;
if (getDriverSpecificDetectionFn(gpu->vendor.chars, &detectFn, &dllName) && (options->temp || options->driverSpecific))
if (options->driverSpecific && getDriverSpecificDetectionFn(gpu->vendor.chars, &detectFn, &dllName))
{
unsigned vendorId = 0, deviceId = 0, subSystemId = 0, revId = 0;
if (SetupDiGetDeviceRegistryPropertyW(hdev, &did, SPDRP_HARDWAREID, NULL, (PBYTE) buffer, sizeof(buffer), NULL))
{
swscanf(buffer, L"PCI\\VEN_%x&DEV_%x&SUBSYS_%x&REV_%x", &vendorId, &deviceId, &subSystemId, &revId);
ffStrbufSetStatic(&gpu->vendor, ffGPUGetVendorString(vendorId));
}
detectFn(
&(FFGpuDriverCondition) {
.type = FF_GPU_DRIVER_CONDITION_TYPE_DEVICE_ID
.type = (deviceId > 0 ? FF_GPU_DRIVER_CONDITION_TYPE_DEVICE_ID : 0)
| (adapterLuid > 0 ? FF_GPU_DRIVER_CONDITION_TYPE_LUID : 0)
| (pciAddr > 0 ? FF_GPU_DRIVER_CONDITION_TYPE_BUS_ID : 0),
.pciDeviceId = {
@@ -189,9 +214,93 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
if (!gpu->name.length)
{
if (SetupDiGetDeviceRegistryPropertyW(hdev, &did, SPDRP_DEVICEDESC, NULL, (PBYTE) buffer, sizeof(buffer), NULL))
bufferLen = sizeof(buffer);
if (CM_Get_DevNode_Registry_PropertyW(devInst, CM_DRP_DEVICEDESC, NULL, buffer, &bufferLen, 0) == CR_SUCCESS)
ffStrbufSetWS(&gpu->name, buffer);
}
if (gpu->type == FF_GPU_TYPE_UNKNOWN && adapterLuid > 0)
{
HMODULE hgdi32 = GetModuleHandleW(L"gdi32.dll");
if (hgdi32)
{
FF_LIBRARY_LOAD_SYMBOL_LAZY(hgdi32, D3DKMTOpenAdapterFromLuid);
if (ffD3DKMTOpenAdapterFromLuid) // Windows 8 and later
{
D3DKMT_OPENADAPTERFROMLUID openAdapterFromLuid = { .AdapterLuid = *(LUID*)&adapterLuid };
if (NT_SUCCESS(ffD3DKMTOpenAdapterFromLuid(&openAdapterFromLuid)))
{
D3DKMT_ADAPTERTYPE adapterType = {};
D3DKMT_QUERYADAPTERINFO queryAdapterInfo = {
.hAdapter = openAdapterFromLuid.hAdapter,
.Type = KMTQAITYPE_ADAPTERTYPE,
.pPrivateDriverData = &adapterType,
.PrivateDriverDataSize = sizeof(adapterType),
};
if (NT_SUCCESS(D3DKMTQueryAdapterInfo(&queryAdapterInfo))) // Vista and later
{
if (adapterType.HybridDiscrete)
gpu->type = FF_GPU_TYPE_DISCRETE;
else if (adapterType.HybridIntegrated)
gpu->type = FF_GPU_TYPE_INTEGRATED;
}
if (gpu->frequency == FF_GPU_FREQUENCY_UNSET)
{
for (ULONG nodeIdx = 0; ; nodeIdx++)
{
D3DKMT_NODEMETADATA nodeMetadata = {
.NodeOrdinalAndAdapterIndex = (0 << 16) | nodeIdx,
};
queryAdapterInfo = (D3DKMT_QUERYADAPTERINFO) {
.hAdapter = openAdapterFromLuid.hAdapter,
.Type = KMTQAITYPE_NODEMETADATA,
.pPrivateDriverData = &nodeMetadata,
.PrivateDriverDataSize = sizeof(nodeMetadata),
};
if (!NT_SUCCESS(D3DKMTQueryAdapterInfo(&queryAdapterInfo))) break; // Windows 10 and later
if (nodeMetadata.NodeData.EngineType != DXGK_ENGINE_TYPE_3D) continue;
D3DKMT_QUERYSTATISTICS queryStatistics = {
.Type = D3DKMT_QUERYSTATISTICS_NODE2,
.AdapterLuid = *(LUID*)&adapterLuid,
.QueryNode2 = { .PhysicalAdapterIndex = 0, .NodeOrdinal = (UINT16) nodeIdx },
};
if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) // Windows 11 (22H2) and later
{
gpu->frequency = (uint32_t) (queryStatistics.QueryResult.NodeInformation.NodePerfData.MaxFrequency / 1000 / 1000);
break;
}
}
}
D3DKMT_CLOSEADAPTER closeAdapter = { .hAdapter = openAdapterFromLuid.hAdapter };
(void) D3DKMTCloseAdapter(&closeAdapter);
openAdapterFromLuid.hAdapter = 0;
}
if (options->temp && gpu->temperature != gpu->temperature)
{
D3DKMT_QUERYSTATISTICS queryStatistics = {
.Type = D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER,
.AdapterLuid = *(LUID*)&adapterLuid,
.QueryPhysAdapter = { .PhysicalAdapterIndex = 0 },
};
if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics)) &&
queryStatistics.QueryResult.PhysAdapterInformation.AdapterPerfData.Temperature != 0)
gpu->temperature = queryStatistics.QueryResult.PhysAdapterInformation.AdapterPerfData.Temperature / 10.0;
}
}
}
}
if (gpu->type == FF_GPU_TYPE_UNKNOWN)
{
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL)
gpu->type = gpu->deviceId == 20 ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
else if (gpu->dedicated.total != FF_GPU_VMEM_SIZE_UNSET)
gpu->type = gpu->dedicated.total >= 1024 * 1024 * 1024 ? FF_GPU_TYPE_DISCRETE : FF_GPU_TYPE_INTEGRATED;
}
}
return NULL;
+9
View File
@@ -23,6 +23,13 @@ typedef enum NvApiGPUMemoryType
NVAPI_GPU_MEMORY_TYPE_GDDR7,
} NvApiGPUMemoryType;
typedef enum
{
NV_SYSTEM_TYPE_GPU_UNKNOWN = 0,
NV_SYSTEM_TYPE_IGPU = 1, // Integrated
NV_SYSTEM_TYPE_DGPU = 2, // Discrete
} NvApiGPUType;
typedef int NvAPI_Status; // 0 = success; < 0 = error
typedef struct NvPhysicalGpuHandle* NvPhysicalGpuHandle;
@@ -32,6 +39,7 @@ typedef enum
NVAPI_INTERFACE_OFFSET_UNLOAD = 0xD22BDD7E,
NVAPI_INTERFACE_OFFSET_ENUM_PHYSICAL_GPUS = 0xE5AC921F,
NVAPI_INTERFACE_OFFSET_GPU_GET_RAM_TYPE = 0x57F7CAAC,
NVAPI_INTERFACE_OFFSET_GPU_GET_GPU_TYPE = 0xC33BAEB1,
NVAPI_INTERFACE_OFFSET_FORCE_UINT32 = 0xFFFFFFFF
} NvApiInterfaceOffsets;
@@ -42,3 +50,4 @@ extern NvAPI_Status nvapi_Initialize(void);
extern NvAPI_Status nvapi_Unload(void);
extern NvAPI_Status nvapi_EnumPhysicalGPUs(NvPhysicalGpuHandle* handles, int* count);
extern NvAPI_Status nvapi_GPU_GetRamType(NvPhysicalGpuHandle handle, NvApiGPUMemoryType* memtype);
extern NvAPI_Status nvapi_GPU_GetGPUType(NvPhysicalGpuHandle handle, NvApiGPUType* gpuType);
+19 -2
View File
@@ -291,6 +291,21 @@ FF_MAYBE_UNUSED static bool detectDebianDerived(FFOSResult* result)
return false;
}
FF_MAYBE_UNUSED static bool detectFedoraVariant(FFOSResult* result)
{
if (ffStrbufEqualS(&result->variantID, "coreos")
|| ffStrbufEqualS(&result->variantID, "kinoite")
|| ffStrbufEqualS(&result->variantID, "sericea")
|| ffStrbufEqualS(&result->variantID, "silverblue"))
{
ffStrbufAppendC(&result->id, '-');
ffStrbufAppend(&result->id, &result->variantID);
ffStrbufSetStatic(&result->idLike, "fedora");
return true;
}
return false;
}
static void detectOS(FFOSResult* os)
{
#ifdef FF_CUSTOM_OS_RELEASE_PATH
@@ -341,13 +356,15 @@ void ffDetectOSImpl(FFOSResult* os)
detectOS(os);
#ifdef __linux__
if(ffStrbufIgnCaseEqualS(&os->id, "ubuntu"))
if(ffStrbufEqualS(&os->id, "ubuntu"))
getUbuntuFlavour(os);
else if(ffStrbufIgnCaseEqualS(&os->id, "debian"))
else if(ffStrbufEqualS(&os->id, "debian"))
{
if (!detectDebianDerived(os))
getDebianVersion(os);
}
else if(ffStrbufEqualS(&os->id, "fedora"))
detectFedoraVariant(os);
else if(ffStrbufEqualS(&os->id, "linuxmint"))
{
if (ffStrbufEqualS(&os->name, "LMDE"))
+15 -18
View File
@@ -646,33 +646,30 @@ void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options)
#endif
ffStrbufSet(&baseDir, &instance.state.platform.homeDir);
if (!(options->disabled & FF_PACKAGES_FLAG_NIX_BIT))
{
// check if ~/.nix-profile exists
FF_STRBUF_AUTO_DESTROY profilePath = ffStrbufCreateCopy(&baseDir);
ffStrbufAppendS(&profilePath, ".nix-profile");
if (ffPathExists(profilePath.chars, FF_PATHTYPE_DIRECTORY))
{
result->nixUser += getNixPackages(&baseDir, ".nix-profile");
}
// Count packages from $HOME/.nix-profile
result->nixUser += getNixPackages(&baseDir, ".nix-profile");
// check if $XDG_STATE_HOME/nix/profile exists
FF_STRBUF_AUTO_DESTROY stateDir = ffStrbufCreate();
const char* stateHome = getenv("XDG_STATE_HOME");
if(ffStrSet(stateHome))
// Check in $XDG_STATE_HOME/nix/profile
FF_STRBUF_AUTO_DESTROY stateHome = ffStrbufCreate();
const char* stateHomeEnv = getenv("XDG_STATE_HOME");
if (ffStrSet(stateHomeEnv))
{
ffStrbufSetS(&stateDir, stateHome);
ffStrbufEnsureEndsWithC(&stateDir, '/');
ffStrbufSetS(&stateHome, stateHomeEnv);
ffStrbufEnsureEndsWithC(&stateHome, '/');
}
else
{
ffStrbufSet(&stateDir, &instance.state.platform.homeDir);
ffStrbufAppendS(&stateDir, ".local/state/");
ffStrbufSet(&stateHome, &instance.state.platform.homeDir);
ffStrbufAppendS(&stateHome, ".local/state/");
}
result->nixUser += getNixPackages(&stateHome, "nix/profile");
ffStrbufSet(&profilePath, &stateDir);
ffStrbufAppendS(&profilePath, "nix/profile");
result->nixUser += getNixPackages(&stateDir, "nix/profile");
// Check in /etc/profiles/per-user/$USER
FF_STRBUF_AUTO_DESTROY userPkgsDir = ffStrbufCreateStatic("/etc/profiles/per-user/");
result->nixUser += getNixPackages(&userPkgsDir, instance.state.platform.userName.chars);
}
if (!(options->disabled & FF_PACKAGES_FLAG_GUIX_BIT))
@@ -113,9 +113,9 @@ const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
if (deviceCharacteristics)
{
ffCfDictGetString(deviceCharacteristics, CFSTR(kIOPropertyProductSerialNumberKey), &device->serial);
ffStrbufTrim(&device->serial, ' ');
ffStrbufTrimSpace(&device->serial);
ffCfDictGetString(deviceCharacteristics, CFSTR(kIOPropertyProductRevisionLevelKey), &device->revision);
ffStrbufTrim(&device->revision, ' ');
ffStrbufTrimRightSpace(&device->revision);
CFStringRef mediumType = (CFStringRef) CFDictionaryGetValue(deviceCharacteristics, CFSTR(kIOPropertyMediumTypeKey));
if (mediumType)
@@ -65,7 +65,7 @@ const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
FFPhysicalDiskResult* device = (FFPhysicalDiskResult*) ffListAdd(result);
ffStrbufInitF(&device->devPath, "/dev/%s", provider->lg_name);
ffStrbufInitMove(&device->serial, &identifier);
ffStrbufTrim(&device->serial, ' ');
ffStrbufTrimSpace(&device->serial);
ffStrbufInit(&device->revision);
ffStrbufInit(&device->interconnect);
switch (snapIter->device_type & DEVSTAT_TYPE_IF_MASK)
@@ -153,7 +153,7 @@ static void parsePhysicalDisk(int dfd, const char* devName, FFPhysicalDiskOption
{
ffStrbufInit(&device->serial);
if (ffReadFileBufferRelative(devfd, "serial", &device->serial))
ffStrbufTrim(&device->serial, ' ');
ffStrbufTrimSpace(&device->serial);
}
{
@@ -36,9 +36,15 @@ static int walkDevTree(di_node_t node, di_minor_t minor, struct FFWalkTreeBundle
char* buf;
if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "inquiry-serial-no", &buf) > 0)
{
ffStrbufSetS(&device->serial, buf);
ffStrbufTrimSpace(&device->serial);
}
if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "inquiry-revision-id", &buf) > 0)
{
ffStrbufSetS(&device->revision, buf);
ffStrbufTrimRightSpace(&device->revision);
}
if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, "class", &buf) > 0)
ffStrbufSetS(&device->interconnect, buf);
@@ -62,14 +62,14 @@ static bool detectPhysicalDisk(const wchar_t* szDevice, FFlist* result, FFPhysic
if (sdd->SerialNumberOffset != 0)
{
ffStrbufSetS(&device->serial, (const char*) sddBuffer + sdd->SerialNumberOffset);
ffStrbufTrim(&device->serial, ' ');
ffStrbufTrimSpace(&device->serial);
}
ffStrbufInit(&device->revision);
if (sdd->ProductRevisionOffset != 0)
{
ffStrbufSetS(&device->revision, (const char*) sddBuffer + sdd->ProductRevisionOffset);
ffStrbufTrim(&device->revision, ' ');
ffStrbufTrimRightSpace(&device->revision);
}
device->type |= sdd->RemovableMedia ? FF_PHYSICALDISK_TYPE_REMOVABLE : FF_PHYSICALDISK_TYPE_FIXED;
+23 -11
View File
@@ -32,15 +32,6 @@ const char* ffDetectSound(FFlist* devices /* List of FFSoundDevice */)
{
AudioDeviceID deviceId = deviceIds[index];
FF_CFTYPE_AUTO_RELEASE CFStringRef name = NULL;
dataSize = sizeof(name);
if(AudioObjectGetPropertyData(deviceId, &(AudioObjectPropertyAddress){
kAudioObjectPropertyName,
kAudioObjectPropertyScopeOutput,
kAudioObjectPropertyElementMain
}, 0, NULL, &dataSize, &name) != kAudioHardwareNoError)
continue;
// Ignore input devices
if(AudioObjectGetPropertyDataSize(deviceId, &(AudioObjectPropertyAddress){
kAudioDevicePropertyStreams,
@@ -71,10 +62,31 @@ const char* ffDetectSound(FFlist* devices /* List of FFSoundDevice */)
device->main = deviceId == mainDeviceId;
device->active = false;
device->volume = FF_SOUND_VOLUME_UNKNOWN;
ffStrbufInitF(&device->identifier, "%u", (unsigned) deviceId);
ffStrbufInit(&device->identifier);
ffStrbufInit(&device->name);
ffStrbufInitStatic(&device->platformApi, "Core Audio");
ffCfStrGetString(name, &device->name);
FF_CFTYPE_AUTO_RELEASE CFStringRef uid = NULL;
dataSize = sizeof(uid);
if(AudioObjectGetPropertyData(deviceId, &(AudioObjectPropertyAddress) {
kAudioDevicePropertyDeviceUID,
kAudioObjectPropertyScopeOutput,
kAudioObjectPropertyElementMain
}, 0, NULL, &dataSize, &uid) == kAudioHardwareNoError)
ffCfStrGetString(uid, &device->identifier);
else
ffStrbufAppendF(&device->identifier, "ID-%u", (unsigned) deviceId);
FF_CFTYPE_AUTO_RELEASE CFStringRef name = NULL;
dataSize = sizeof(name);
if(AudioObjectGetPropertyData(deviceId, &(AudioObjectPropertyAddress){
kAudioObjectPropertyName,
kAudioObjectPropertyScopeOutput,
kAudioObjectPropertyElementMain
}, 0, NULL, &dataSize, &name) == kAudioHardwareNoError)
ffCfStrGetString(name, &device->name);
else
ffStrbufSet(&device->name, &device->identifier);
uint32_t muted;
dataSize = sizeof(muted);
+16
View File
@@ -0,0 +1,16 @@
▂🬭𜴧⎻𜷗𜴗𜴦𜵎⎻𜴧🬭▂
▁▂𜴧━𜵼𜵶𜶮▂🬭🬭𜴐🭗 🬁𜴜🬭🬭▂𜶮▁𜵁━𜴧▂▁
𜷓𜵐🬂🬂🮂𜶮𜴸𜴪━𜴆🮂▔ ▔🮂𜴆━𜴩𜵳𜴸🮂🬂🬂𜶚🬿
🭄🬨▍ 🬜🮂▔ ▁▂▂🬭🬭▂▂▁ ▔🮂🬪 🮈🬕𜶿
🭄🭙▐▎𜵫 🭃██████████🭎 🭢𜶡🮇▌🭤𜶿
🭄🭙 ▐🭄🭙 🭋█████🭜𜴦█████🭀 🭤🭏▌ 🭤🭏
𜵫🭗 🮉🭛 🭃███🭝🭙 🭥🭒███🭎 🭦▋ 🭢𜶡
▟🬮𜴧━🭷🭘 🭋████▄▂ ▂▄████🭀 🭣𜴇━𜴧🬯🭏
🭕𜴸𜴆╾🭺🬽 🭃██🭡 🭖██🭐 🭈𜵡╼𜴆🬡🭠
𜴤🬼 🮉🭀 🭋███΄ 🭤███🭀 🭋▊ 🭇𜵐
𜴠🬾 ▐𜴢🬾▁▁ 🭃██𜴍 𜶘██🭐 ▁▁🭉🭫▌ 🭉🭠
𜴠🬾🮈▎𜶚 ▔🮂🬂▀🬎🬎 🮅🬎▀🬂🮂▔ 𜵐🮇▌🭉𜴏
𜴢🭿▍ 𜴬▂▁ ▁▂🬜΄🮈🬲𜴏
🭥𜶡🬭🬭▂𜶭▁𜵁━𜴧▂▁ ▁▂𜴧━𜶷𜶭𜶮▂🬭🬭𜵫🭚
▔⎺𜴆━𜴩▔𜶮🮂🬂🬂𜴜🬼 🭇𜴐🬂🬂🮂𜶮▔𜴨━𜴆⎺▔
⠈🮂🭷𜴆╾𜶦𜷞🭄𜴬╼𜴆🬂🮂΄
+18
View File
@@ -0,0 +1,18 @@
#####
#####
#####
######
######
#####
##### #####
###### #####
###### #####
###### ######
##### ######
##### #####
#####
######
######
######
#####
#####
+33 -18
View File
@@ -11,16 +11,6 @@ const FFlogo ffLogoUnknown = {
};
static const FFlogo A[] = {
//Ada
{
.names = {"Ada"},
.lines = FASTFETCH_DATATEXT_LOGO_ADA,
.colors = {
FF_COLOR_FG_256 "15",
FF_COLOR_FG_256 "14",
FF_COLOR_FG_256 "16",
}
},
// Adélie
{
.names = {"Adélie", "Adelie"},
@@ -701,6 +691,15 @@ static const FFlogo A[] = {
FF_COLOR_FG_WHITE,
},
},
// AxOS
{
.names = {"AxOS"},
.lines = FASTFETCH_DATATEXT_LOGO_AXOS,
.colors = {
FF_COLOR_FG_RGB "222;6;255",
FF_COLOR_FG_RGB "222;6;255",
},
},
// Azos
{
.names = {"Azos"},
@@ -1771,8 +1770,7 @@ static const FFlogo F[] = {
},
// FedoraSilverblue
{
.names = {"Fedora_silverblue", "fedora-silverblue"},
.type = FF_LOGO_LINE_TYPE_ALTER_BIT,
.names = {"Fedora-Silverblue"},
.lines = FASTFETCH_DATATEXT_LOGO_FEDORA_SILVERBLUE,
.colors = {
FF_COLOR_FG_BLUE,
@@ -1784,8 +1782,7 @@ static const FFlogo F[] = {
},
// FedoraKinoite
{
.names = {"Fedora_kinoite", "fedora-kinoite"},
.type = FF_LOGO_LINE_TYPE_ALTER_BIT,
.names = {"Fedora-Kinoite"},
.lines = FASTFETCH_DATATEXT_LOGO_FEDORA_KINOITE,
.colors = {
FF_COLOR_FG_BLUE,
@@ -1796,8 +1793,7 @@ static const FFlogo F[] = {
},
// FedoraSericea
{
.names = {"Fedora_sericea", "fedora-sericea"},
.type = FF_LOGO_LINE_TYPE_ALTER_BIT,
.names = {"Fedora-Sericea"},
.lines = FASTFETCH_DATATEXT_LOGO_FEDORA_SERICEA,
.colors = {
FF_COLOR_FG_BLUE,
@@ -1808,8 +1804,7 @@ static const FFlogo F[] = {
},
// FedoraCoreOS
{
.names = {"Fedora_coreos", "fedora-coreos"},
.type = FF_LOGO_LINE_TYPE_ALTER_BIT,
.names = {"Fedora-CoreOS"},
.lines = FASTFETCH_DATATEXT_LOGO_FEDORA_COREOS,
.colors = {
FF_COLOR_FG_BLUE,
@@ -3109,6 +3104,16 @@ static const FFlogo M[] = {
.colorKeys = FF_COLOR_FG_LIGHT_BLACK,
.colorTitle = FF_COLOR_FG_DEFAULT,
},
// Minimal System
{
.names = {"Minimal_System"},
.lines = FASTFETCH_DATATEXT_LOGO_MINIMAL,
.colors = {
FF_COLOR_FG_RED,
},
.colorKeys = FF_COLOR_FG_CYAN,
.colorTitle = FF_COLOR_FG_DEFAULT,
},
// Minix
{
.names = {"Minix"},
@@ -5391,6 +5396,16 @@ static const FFlogo X[] = {
FF_COLOR_FG_DEFAULT,
},
},
//Xray_OS
{
.names = {"Xray_OS"},
.lines = FASTFETCH_DATATEXT_LOGO_XRAY_OS,
.colors = {
FF_COLOR_FG_256 "15",
FF_COLOR_FG_256 "14",
FF_COLOR_FG_256 "16",
}
},
// LAST
{},
};
+61 -29
View File
@@ -436,6 +436,13 @@ static void logoPrintNone(void)
static bool logoPrintBuiltinIfExists(const FFstrbuf* name, FFLogoSize size)
{
if(name->chars[0] == '~' || name->chars[0] == '.' || name->chars[0] == '/'
#if _WIN32
|| (ffCharIsEnglishAlphabet(name->chars[0]) && name->chars[1] == ':') // Windows drive letter
#endif
)
return false; // Paths
if(ffStrbufIgnCaseEqualS(name, "none"))
{
logoPrintNone();
@@ -466,21 +473,22 @@ static bool logoPrintData(bool doColorReplacement, FFstrbuf* source)
return true;
}
static void updateLogoPath(void)
static bool updateLogoPath(void)
{
FFOptionsLogo* options = &instance.config.logo;
if(ffPathExists(options->source.chars, FF_PATHTYPE_FILE))
return;
return true;
if (ffStrbufEqualS(&options->source, "-")) // stdin
return;
return true;
FF_STRBUF_AUTO_DESTROY fullPath = ffStrbufCreate();
if (ffPathExpandEnv(options->source.chars, &fullPath) && ffPathExists(fullPath.chars, FF_PATHTYPE_FILE))
{
ffStrbufSet(&options->source, &fullPath);
return;
ffStrbufDestroy(&options->source);
ffStrbufInitMove(&options->source, &fullPath);
return true;
}
FF_LIST_FOR_EACH(FFstrbuf, dataDir, instance.state.platform.dataDirs)
@@ -492,10 +500,13 @@ static void updateLogoPath(void)
if(ffPathExists(fullPath.chars, FF_PATHTYPE_FILE))
{
ffStrbufSet(&options->source, &fullPath);
break;
ffStrbufDestroy(&options->source);
ffStrbufInitMove(&options->source, &fullPath);
return true;
}
}
return false;
}
static bool logoPrintFileIfExists(bool doColorReplacement, bool raw)
@@ -579,7 +590,13 @@ static bool logoTryKnownType(void)
return logoPrintData(false, &source);
}
updateLogoPath(); //We sure have a file, resolve relative paths
//We sure have a file, resolve relative paths
if (!updateLogoPath())
{
if (instance.config.display.showErrors)
fprintf(stderr, "Logo: Failed to resolve logo source: %s\n", options->source.chars);
return false;
}
if(options->type == FF_LOGO_TYPE_FILE)
return logoPrintFileIfExists(true, false);
@@ -642,31 +659,46 @@ void ffLogoPrint(void)
return;
//Make sure the logo path is set correctly.
updateLogoPath();
if (updateLogoPath())
{
if (ffStrbufEndsWithIgnCaseS(&options->source, ".raw"))
{
if(logoPrintFileIfExists(false, true))
return;
}
const FFTerminalResult* terminal = ffDetectTerminal();
if (!ffStrbufEndsWithIgnCaseS(&options->source, ".txt"))
{
const FFTerminalResult* terminal = ffDetectTerminal();
//Terminal emulators that support kitty graphics protocol.
bool supportsKitty =
ffStrbufIgnCaseEqualS(&terminal->processName, "kitty") ||
ffStrbufIgnCaseEqualS(&terminal->processName, "konsole") ||
ffStrbufIgnCaseEqualS(&terminal->processName, "wezterm") ||
ffStrbufIgnCaseEqualS(&terminal->processName, "wayst") ||
ffStrbufIgnCaseEqualS(&terminal->processName, "ghostty") ||
#ifdef __APPLE__
ffStrbufIgnCaseEqualS(&terminal->processName, "WarpTerminal") ||
#else
ffStrbufIgnCaseEqualS(&terminal->processName, "warp") ||
#endif
false;
//Terminal emulators that support kitty graphics protocol.
bool supportsKitty =
ffStrbufIgnCaseEqualS(&terminal->processName, "kitty") ||
ffStrbufIgnCaseEqualS(&terminal->processName, "konsole") ||
ffStrbufIgnCaseEqualS(&terminal->processName, "wezterm") ||
ffStrbufIgnCaseEqualS(&terminal->processName, "wayst") ||
ffStrbufIgnCaseEqualS(&terminal->processName, "ghostty") ||
#ifdef __APPLE__
ffStrbufIgnCaseEqualS(&terminal->processName, "WarpTerminal") ||
#else
ffStrbufIgnCaseEqualS(&terminal->processName, "warp") ||
#endif
false;
//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))
return;
//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))
return;
}
//Try to load the logo as a file. If it succeeds, print it and return.
if(logoPrintFileIfExists(true, false))
return;
//Try to load the logo as a file. If it succeeds, print it and return.
if(logoPrintFileIfExists(true, false))
return;
}
else
{
if (instance.config.display.showErrors)
fprintf(stderr, "Logo: Failed to resolve logo source: %s\n", options->source.chars);
}
logoPrintDetected(FF_LOGO_SIZE_UNKNOWN);
}
+9 -1
View File
@@ -125,7 +125,8 @@ static void printDisk(FFDiskOptions* options, const FFDisk* disk, uint32_t index
bool isHidden = !!(disk->type & FF_DISK_VOLUME_TYPE_HIDDEN_BIT);
bool isReadOnly = !!(disk->type & FF_DISK_VOLUME_TYPE_READONLY_BIT);
uint64_t duration = ffTimeGetNow() - disk->createTime;
uint64_t now = ffTimeGetNow();
uint64_t duration = now - disk->createTime;
uint32_t milliseconds = (uint32_t) (duration % 1000);
duration /= 1000;
uint32_t seconds = (uint32_t) (duration % 60);
@@ -136,6 +137,7 @@ static void printDisk(FFDiskOptions* options, const FFDisk* disk, uint32_t index
duration /= 24;
uint32_t days = (uint32_t) duration;
FFTimeGetAgeResult age = ffTimeGetAge(disk->createTime, now);
FF_PRINT_FORMAT_CHECKED(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY, ((FFformatarg[]) {
FF_FORMAT_ARG(usedPretty, "size-used"),
FF_FORMAT_ARG(totalPretty, "size-total"),
@@ -158,6 +160,9 @@ static void printDisk(FFDiskOptions* options, const FFDisk* disk, uint32_t index
FF_FORMAT_ARG(milliseconds, "milliseconds"),
FF_FORMAT_ARG(disk->mountpoint, "mountpoint"),
FF_FORMAT_ARG(disk->mountFrom, "mount-from"),
FF_FORMAT_ARG(age.years, "years"),
FF_FORMAT_ARG(age.daysOfYear, "days-of-year"),
FF_FORMAT_ARG(age.yearsFraction, "years-fraction"),
}));
}
}
@@ -523,6 +528,9 @@ static FFModuleBaseInfo ffModuleInfo = {
{"Milliseconds after creation", "milliseconds"},
{"Mount point / drive letter", "mountpoint"},
{"Mount from (device path)", "mount-from"},
{"Years integer after creation", "years"},
{"Days of year after creation", "days-of-year"},
{"Years fraction after creation", "years-fraction"},
}))
};
-5
View File
@@ -188,11 +188,6 @@ static FFModuleBaseInfo ffModuleInfo = {
.parseJsonObject = (void*) ffParseSeparatorJsonObject,
.printModule = (void*) ffPrintSeparator,
.generateJsonConfig = (void*) ffGenerateSeparatorJsonConfig,
.formatArgs = FF_FORMAT_ARG_LIST(((FFModuleFormatArg[]) {
{"Separator string", "string"},
{"Output color", "outputColor"},
{"Length", "length"},
}))
};
void ffInitSeparatorOptions(FFSeparatorOptions* options)
+13 -5
View File
@@ -39,6 +39,8 @@ void ffPrintUptime(FFUptimeOptions* options)
uptime /= 24;
uint32_t days = (uint32_t) uptime;
FFTimeGetAgeResult age = ffTimeGetAge(result.bootTime, ffTimeGetNow());
FF_PRINT_FORMAT_CHECKED(FF_UPTIME_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]){
FF_FORMAT_ARG(days, "days"),
FF_FORMAT_ARG(hours, "hours"),
@@ -46,6 +48,9 @@ void ffPrintUptime(FFUptimeOptions* options)
FF_FORMAT_ARG(seconds, "seconds"),
FF_FORMAT_ARG(milliseconds, "milliseconds"),
{FF_FORMAT_ARG_TYPE_STRING, ffTimeToShortStr(result.bootTime), "boot-time"},
FF_FORMAT_ARG(age.years, "years"),
FF_FORMAT_ARG(age.daysOfYear, "days-of-year"),
FF_FORMAT_ARG(age.yearsFraction, "years-fraction"),
}));
}
}
@@ -110,12 +115,15 @@ static FFModuleBaseInfo ffModuleInfo = {
.generateJsonResult = (void*) ffGenerateUptimeJsonResult,
.generateJsonConfig = (void*) ffGenerateUptimeJsonConfig,
.formatArgs = FF_FORMAT_ARG_LIST(((FFModuleFormatArg[]) {
{"Days", "days"},
{"Hours", "hours"},
{"Minutes", "minutes"},
{"Seconds", "seconds"},
{"Milliseconds", "milliseconds"},
{"Days after boot", "days"},
{"Hours after boot", "hours"},
{"Minutes after boot", "minutes"},
{"Seconds after boot", "seconds"},
{"Milliseconds after boot", "milliseconds"},
{"Boot time in local timezone", "boot-time"},
{"Years integer after boot", "years"},
{"Days of year after boot", "days-of-year"},
{"Years fraction after boot", "years-fraction"},
}))
};
+8
View File
@@ -78,6 +78,8 @@ void ffPrintUsers(FFUsersOptions* options)
duration /= 24;
uint32_t days = (uint32_t) duration;
FFTimeGetAgeResult age = ffTimeGetAge(user->loginTime, ffTimeGetNow());
FF_PRINT_FORMAT_CHECKED(FF_USERS_MODULE_NAME, users.length == 1 ? 0 : (uint8_t) (i + 1), &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]){
FF_FORMAT_ARG(user->name, "name"),
FF_FORMAT_ARG(user->hostName, "host-name"),
@@ -89,6 +91,9 @@ void ffPrintUsers(FFUsersOptions* options)
FF_FORMAT_ARG(minutes, "minutes"),
FF_FORMAT_ARG(seconds, "seconds"),
FF_FORMAT_ARG(milliseconds, "milliseconds"),
FF_FORMAT_ARG(age.years, "years"),
FF_FORMAT_ARG(age.daysOfYear, "days-of-year"),
FF_FORMAT_ARG(age.yearsFraction, "years-fraction"),
}));
}
}
@@ -222,6 +227,9 @@ static FFModuleBaseInfo ffModuleInfo = {
{"Minutes after login", "minutes"},
{"Seconds after login", "seconds"},
{"Milliseconds after login", "milliseconds"},
{"Years integer after login", "years"},
{"Days of year after login", "days-of-year"},
{"Years fraction after login", "years-fraction"},
}))
};
+20
View File
@@ -221,6 +221,23 @@ const char* ffOptionsParseDisplayJsonConfig(FFOptionsDisplay* options, yyjson_va
else
return "display.bar must be an object";
}
else if (ffStrEqualsIgnCase(key, "fraction"))
{
if (yyjson_is_obj(val))
{
yyjson_val* ndigits = yyjson_obj_get(val, "ndigits");
if (ndigits)
{
if (yyjson_is_null(ndigits))
options->fractionNdigits = -1;
else if (!yyjson_is_int(ndigits))
return "display.fraction.ndigits must be an integer";
options->fractionNdigits = (int8_t) yyjson_get_int(ndigits);
}
}
else
return "display.fraction must be an object";
}
else if (ffStrEqualsIgnCase(key, "noBuffer"))
options->noBuffer = yyjson_get_bool(val);
else if (ffStrEqualsIgnCase(key, "keyWidth"))
@@ -462,6 +479,8 @@ bool ffOptionsParseDisplayCommandLine(FFOptionsDisplay* options, const char* key
else
return false;
}
else if(ffStrEqualsIgnCase(key, "--fraction-ndigits"))
options->fractionNdigits = (int8_t) ffOptionParseInt32(key, value);
else if(ffStrEqualsIgnCase(key, "--no-buffer"))
options->noBuffer = ffOptionParseBoolean(value);
else if(ffStrStartsWithIgnCase(key, "--bar-"))
@@ -539,6 +558,7 @@ void ffOptionsInitDisplay(FFOptionsDisplay* options)
ffStrbufInitStatic(&options->percentColorYellow, instance.state.terminalLightTheme ? FF_COLOR_FG_YELLOW : FF_COLOR_FG_LIGHT_YELLOW);
ffStrbufInitStatic(&options->percentColorRed, instance.state.terminalLightTheme ? FF_COLOR_FG_RED : FF_COLOR_FG_LIGHT_RED);
options->freqNdigits = 2;
options->fractionNdigits = -1;
ffListInit(&options->constants, sizeof(FFstrbuf));
}
+1
View File
@@ -60,6 +60,7 @@ typedef struct FFOptionsDisplay
uint16_t keyWidth;
uint16_t keyPaddingLeft;
int8_t freqNdigits;
int8_t fractionNdigits;
FFlist constants; // list of FFstrbuf
} FFOptionsDisplay;
+25
View File
@@ -272,6 +272,31 @@ void ffStrbufTrimRight(FFstrbuf* strbuf, char c)
strbuf->chars[strbuf->length] = '\0';
}
void ffStrbufTrimLeftSpace(FFstrbuf* strbuf)
{
if(strbuf->length == 0)
return;
uint32_t index = 0;
while(index < strbuf->length && isspace(strbuf->chars[index]))
++index;
if(index == 0)
return;
if(strbuf->allocated == 0)
{
//static string
strbuf->length -= index;
strbuf->chars += index;
return;
}
memmove(strbuf->chars, strbuf->chars + index, strbuf->length - index);
strbuf->length -= index;
strbuf->chars[strbuf->length] = '\0';
}
void ffStrbufTrimRightSpace(FFstrbuf* strbuf)
{
if (strbuf->length == 0)
+8 -1
View File
@@ -53,6 +53,7 @@ FF_C_PRINTF(2, 3) void ffStrbufSetF(FFstrbuf* strbuf, const char* format, ...);
void ffStrbufTrimLeft(FFstrbuf* strbuf, char c);
void ffStrbufTrimRight(FFstrbuf* strbuf, char c);
void ffStrbufTrimLeftSpace(FFstrbuf* strbuf);
void ffStrbufTrimRightSpace(FFstrbuf* strbuf);
bool ffStrbufRemoveSubstr(FFstrbuf* strbuf, uint32_t startIndex, uint32_t endIndex);
@@ -473,7 +474,7 @@ static inline FF_C_NODISCARD bool ffStrbufEndsWithS(const FFstrbuf* strbuf, cons
return ffStrbufEndsWithNS(strbuf, (uint32_t) strlen(end), end);
}
static inline FF_C_NODISCARD bool ffStrbufEndsWithFn(const FFstrbuf* strbuf, int (*fn)(int))
static inline FF_C_NODISCARD bool ffStrbufEndsWithFn(const FFstrbuf* strbuf, int (*const fn)(int))
{
return strbuf->length == 0 ? false :
fn(strbuf->chars[strbuf->length - 1]);
@@ -507,6 +508,12 @@ static inline void ffStrbufTrim(FFstrbuf* strbuf, char c)
ffStrbufTrimLeft(strbuf, c);
}
static inline void ffStrbufTrimSpace(FFstrbuf* strbuf)
{
ffStrbufTrimRightSpace(strbuf);
ffStrbufTrimLeftSpace(strbuf);
}
static inline bool ffStrbufMatchSeparatedS(const FFstrbuf* strbuf, const char* comp, char separator)
{
return ffStrbufMatchSeparatedNS(strbuf, (uint32_t) strlen(comp), comp, separator);
+4 -4
View File
@@ -170,13 +170,13 @@ static void getUserShell(FFPlatform* platform)
static void detectWine(FFstrbuf* buf)
{
static const char *(__cdecl *pwine_get_version)(void);
const char * __cdecl wine_get_version(void);
HMODULE hntdll = GetModuleHandleW(L"ntdll.dll");
if (!hntdll) return;
pwine_get_version = (void *)GetProcAddress(hntdll, "wine_get_version");
if (!pwine_get_version) return;
FF_LIBRARY_LOAD_SYMBOL_LAZY(hntdll, wine_get_version);
if (!ffwine_get_version) return;
ffStrbufAppendS(buf, buf->length ? " - wine " : "wine ");
ffStrbufAppendS(buf, pwine_get_version());
ffStrbufAppendS(buf, ffwine_get_version());
}
static void getSystemReleaseAndVersion(FFPlatformSysinfo* info)
+209
View File
@@ -3,6 +3,8 @@
#include <winnt.h>
#include <winternl.h>
#define D3DKMT_ALIGN64 __attribute__((aligned(8)))
typedef struct _PROCESSOR_POWER_INFORMATION {
ULONG Number;
ULONG MaxMhz;
@@ -23,3 +25,210 @@ NTSTATUS NTAPI NtPowerInformation(
NTSTATUS NTAPI RtlGetVersion(
_Inout_ PRTL_OSVERSIONINFOW lpVersionInformation
);
#if __has_include(<d3dkmthk.h>)
#include <d3dkmthk.h>
#else
typedef UINT D3DKMT_HANDLE;
typedef struct _D3DKMT_OPENADAPTERFROMLUID
{
LUID AdapterLuid;
D3DKMT_HANDLE hAdapter;
} D3DKMT_OPENADAPTERFROMLUID;
EXTERN_C _Check_return_ NTSTATUS APIENTRY D3DKMTOpenAdapterFromLuid(_Inout_ CONST D3DKMT_OPENADAPTERFROMLUID*);
typedef struct _D3DKMT_CLOSEADAPTER
{
D3DKMT_HANDLE hAdapter; // in: adapter handle
} D3DKMT_CLOSEADAPTER;
EXTERN_C _Check_return_ NTSTATUS APIENTRY D3DKMTCloseAdapter(_In_ CONST D3DKMT_CLOSEADAPTER*);
typedef struct _D3DKMT_ADAPTERTYPE
{
union
{
struct
{
UINT RenderSupported : 1; // WDDM 1.2, Windows 8
UINT DisplaySupported : 1;
UINT SoftwareDevice : 1;
UINT PostDevice : 1;
UINT HybridDiscrete : 1; // WDDM 1.3, Windows 8.1
UINT HybridIntegrated : 1;
UINT IndirectDisplayDevice : 1;
UINT Paravirtualized : 1; // WDDM 2.3, Windows 10 Fall Creators Update (version 1709)
UINT ACGSupported : 1;
UINT SupportSetTimingsFromVidPn : 1;
UINT Detachable : 1;
UINT ComputeOnly : 1; // WDDM 2.6, Windows 10 May 2019 Update (Version 1903)
UINT Prototype : 1;
UINT RuntimePowerManagement : 1; // WDDM 2.9, Windows 10 Insider Preview "Iron"
UINT Reserved : 18;
};
UINT Value;
};
} D3DKMT_ADAPTERTYPE;
typedef enum _KMTQUERYADAPTERINFOTYPE
{
KMTQAITYPE_ADAPTERTYPE = 15, // WDDM 1.2, Windows 8
KMTQAITYPE_NODEMETADATA = 25, // WDDM 2.0, Windows 10
} KMTQUERYADAPTERINFOTYPE;
typedef struct _D3DKMT_QUERYADAPTERINFO
{
D3DKMT_HANDLE hAdapter;
KMTQUERYADAPTERINFOTYPE Type;
VOID* pPrivateDriverData;
UINT PrivateDriverDataSize;
} D3DKMT_QUERYADAPTERINFO;
EXTERN_C _Check_return_ NTSTATUS APIENTRY D3DKMTQueryAdapterInfo(_Inout_ CONST D3DKMT_QUERYADAPTERINFO*);
typedef enum _D3DKMT_QUERYSTATISTICS_TYPE
{
D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER = 10, // WDDM 2.4, Windows 10 April 2018 Update (version 1803)
D3DKMT_QUERYSTATISTICS_NODE2 = 18, // WDDM 3.1, Windows 11 2022 Update (version 22H2)
} D3DKMT_QUERYSTATISTICS_TYPE;
typedef struct _D3DKMT_QUERYSTATISTICS_QUERY_PHYSICAL_ADAPTER
{
ULONG PhysicalAdapterIndex;
} D3DKMT_QUERYSTATISTICS_QUERY_PHYSICAL_ADAPTER;
typedef struct _D3DKMT_QUERYSTATISTICS_QUERY_NODE2
{
UINT16 PhysicalAdapterIndex;
UINT16 NodeOrdinal;
} D3DKMT_QUERYSTATISTICS_QUERY_NODE2;
typedef struct _D3DKMT_ADAPTER_PERFDATA
{
UINT32 PhysicalAdapterIndex; // in: The physical adapter index, in an LDA chain
D3DKMT_ALIGN64 ULONGLONG MemoryFrequency; // out: Clock frequency of the memory in hertz
D3DKMT_ALIGN64 ULONGLONG MaxMemoryFrequency; // out: Max memory clock frequency
D3DKMT_ALIGN64 ULONGLONG MaxMemoryFrequencyOC; // out: Clock frequency of the memory while overclocked in hertz.
D3DKMT_ALIGN64 ULONGLONG MemoryBandwidth; // out: Amount of memory transferred in bytes
D3DKMT_ALIGN64 ULONGLONG PCIEBandwidth; // out: Amount of memory transferred over PCI-E in bytes
ULONG FanRPM; // out: Fan rpm
ULONG Power; // out: Power draw of the adapter in tenths of a percentage
ULONG Temperature; // out: Temperature in deci-Celsius 1 = 0.1C
UCHAR PowerStateOverride; // out: Overrides dxgkrnls power view of linked adapters.
} D3DKMT_ADAPTER_PERFDATA;
typedef struct _D3DKMT_ADAPTER_PERFDATACAPS
{
UINT32 PhysicalAdapterIndex; // in: The physical adapter index, in an LDA chain
D3DKMT_ALIGN64 ULONGLONG MaxMemoryBandwidth; // out: Max memory bandwidth in bytes for 1 second
D3DKMT_ALIGN64 ULONGLONG MaxPCIEBandwidth; // out: Max pcie bandwidth in bytes for 1 second
ULONG MaxFanRPM; // out: Max fan rpm
ULONG TemperatureMax; // out: Max temperature before damage levels
ULONG TemperatureWarning; // out: The temperature level where throttling begins.
} D3DKMT_ADAPTER_PERFDATACAPS;
#define DXGK_MAX_GPUVERSION_NAME_LENGTH 32
typedef struct _D3DKMT_GPUVERSION
{
UINT32 PhysicalAdapterIndex; // in: The physical adapter index, in an LDA chain
WCHAR BiosVersion[DXGK_MAX_GPUVERSION_NAME_LENGTH]; //out: The gpu bios version
WCHAR GpuArchitecture[DXGK_MAX_GPUVERSION_NAME_LENGTH]; //out: The gpu architectures name.
} D3DKMT_GPUVERSION;
typedef struct _D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER_INFORMATION
{
D3DKMT_ADAPTER_PERFDATA AdapterPerfData;
D3DKMT_ADAPTER_PERFDATACAPS AdapterPerfDataCaps;
D3DKMT_GPUVERSION GpuVersion;
} D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER_INFORMATION;
typedef struct _D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION {
D3DKMT_ALIGN64 UINT64 Reserved[34];
} D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION;
typedef struct _D3DKMT_NODE_PERFDATA
{
UINT32 NodeOrdinal; // in: Node ordinal of the requested engine.
UINT32 PhysicalAdapterIndex; // in: The physical adapter index, in an LDA chain
D3DKMT_ALIGN64 ULONGLONG Frequency; // out: Clock frequency of the engine in hertz
D3DKMT_ALIGN64 ULONGLONG MaxFrequency; // out: Max engine clock frequency
D3DKMT_ALIGN64 ULONGLONG MaxFrequencyOC;// out: Max engine over clock frequency
ULONG Voltage; // out: Voltage of the engine in milli volts mV
ULONG VoltageMax; // out: Max voltage levels in milli volts.
ULONG VoltageMaxOC; // out: Max voltage level while overclocked in milli volts.
// WDDM 2.5
D3DKMT_ALIGN64 ULONGLONG MaxTransitionLatency; // out: Max transition latency to change the frequency in 100 nanoseconds
} D3DKMT_NODE_PERFDATA;
typedef struct _D3DKMT_QUERYSTATISTICS_NODE_INFORMATION {
D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION GlobalInformation; //Global statistics
D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION SystemInformation; //Statistics for system thread
D3DKMT_NODE_PERFDATA NodePerfData;
UINT32 Reserved[3];
} D3DKMT_QUERYSTATISTICS_NODE_INFORMATION;
typedef union _D3DKMT_QUERYSTATISTICS_RESULT
{
D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER_INFORMATION PhysAdapterInformation;
D3DKMT_QUERYSTATISTICS_NODE_INFORMATION NodeInformation;
uint8_t Padding[776];
} D3DKMT_QUERYSTATISTICS_RESULT;
typedef struct _D3DKMT_QUERYSTATISTICS
{
D3DKMT_QUERYSTATISTICS_TYPE Type; // in: type of data requested
LUID AdapterLuid; // in: adapter to get export / statistics from
HANDLE* hProcess; // in: process to get statistics for, if required for this query type
D3DKMT_QUERYSTATISTICS_RESULT QueryResult; // out: requested data
union
{
D3DKMT_QUERYSTATISTICS_QUERY_PHYSICAL_ADAPTER QueryPhysAdapter; // in: id of physical adapter to get statistics for
D3DKMT_QUERYSTATISTICS_QUERY_NODE2 QueryNode2; // in: id of node to get statistics for
};
} D3DKMT_QUERYSTATISTICS;
static_assert(sizeof(D3DKMT_QUERYSTATISTICS) ==
#if _WIN64
0x328
#else
0x320
#endif
, "D3DKMT_QUERYSTATISTICS structure size mismatch");
EXTERN_C _Check_return_ NTSTATUS APIENTRY D3DKMTQueryStatistics(_In_ CONST D3DKMT_QUERYSTATISTICS*);
#define DXGK_MAX_METADATA_NAME_LENGTH 32
typedef enum
{
DXGK_ENGINE_TYPE_OTHER,
DXGK_ENGINE_TYPE_3D,
DXGK_ENGINE_TYPE_VIDEO_DECODE,
DXGK_ENGINE_TYPE_VIDEO_ENCODE,
DXGK_ENGINE_TYPE_VIDEO_PROCESSING,
DXGK_ENGINE_TYPE_SCENE_ASSEMBLY,
DXGK_ENGINE_TYPE_COPY,
DXGK_ENGINE_TYPE_OVERLAY,
DXGK_ENGINE_TYPE_CRYPTO,
DXGK_ENGINE_TYPE_VIDEO_CODEC,
DXGK_ENGINE_TYPE_MAX
} DXGK_ENGINE_TYPE;
typedef struct _DXGK_NODEMETADATA_FLAGS
{
union
{
struct
{
UINT ContextSchedulingSupported : 1; // WDDM 2.2
UINT RingBufferFenceRelease : 1; // WDDM 2.5
UINT SupportTrackedWorkload : 1;
UINT UserModeSubmission : 1;
UINT SupportBuildTestCommandBuffer : 1; // WDDM 3.2
UINT Reserved : 11;
UINT MaxInFlightHwQueueBuffers : 16;
};
UINT32 Value;
};
} DXGK_NODEMETADATA_FLAGS;
typedef struct _DXGK_NODEMETADATA
{
DXGK_ENGINE_TYPE EngineType;
WCHAR FriendlyName[DXGK_MAX_METADATA_NAME_LENGTH];
DXGK_NODEMETADATA_FLAGS Flags; // WDDM 2.2
BOOLEAN GpuMmuSupported; // WDDM 2.0 ???
BOOLEAN IoMmuSupported;
} __attribute__((packed)) DXGK_NODEMETADATA;
typedef struct _D3DKMT_NODEMETADATA
{
_In_ UINT NodeOrdinalAndAdapterIndex; // WDDMv2: High word is physical adapter index, low word is node ordinal
_Out_ DXGK_NODEMETADATA NodeData;
} __attribute__((packed)) D3DKMT_NODEMETADATA;
static_assert(sizeof(D3DKMT_NODEMETADATA) == 0x4E, "D3DKMT_NODEMETADATA structure size mismatch");
#endif
+16
View File
@@ -371,6 +371,22 @@ int main(void)
VERIFY(strbuf.allocated > 0);
ffStrbufDestroy(&strbuf);
//ffStrbufCreateStatic / TrimSpace
ffStrbufInitStatic(&strbuf, "\n TEST\n ");
ffStrbufTrimSpace(&strbuf);
VERIFY(strbuf.length == 4);
VERIFY(strbuf.allocated > 0);
VERIFY(ffStrbufEqualS(&strbuf, "TEST"));
ffStrbufDestroy(&strbuf);
//ffStrbufCreate / TrimSpace
ffStrbufInitS(&strbuf, "\n TEST\n ");
ffStrbufTrimSpace(&strbuf);
VERIFY(strbuf.length == 4);
VERIFY(strbuf.allocated > 0);
VERIFY(ffStrbufEqualS(&strbuf, "TEST"));
ffStrbufDestroy(&strbuf);
//ffStrbufEnsureFixedLengthFree / empty buffer
ffStrbufInit(&strbuf);
ffStrbufEnsureFixedLengthFree(&strbuf, 10);