mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-09-13 02:42:09 +02:00
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:
@@ -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:
|
||||
|
||||
@@ -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
@@ -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"
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
[](https://github.com/fastfetch-cli/fastfetch/releases)
|
||||
[](https://repology.org/project/fastfetch/versions)
|
||||
[](https://repology.org/project/fastfetch/versions)
|
||||
[](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`
|
||||
|
||||
|
||||
Vendored
+6
@@ -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
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
fastfetch_2.46.0_source.buildinfo universe/utils optional
|
||||
fastfetch_2.47.0_source.buildinfo universe/utils optional
|
||||
|
||||
+26
-8
@@ -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",
|
||||
|
||||
@@ -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
@@ -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)) ||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) ¶msGlobal,
|
||||
.pointer = (uintptr_t) ¶msGlobal,
|
||||
.size = sizeof(paramsGlobal),
|
||||
}) >= 0)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"))
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
▂🬭⎻⎻🬭▂
|
||||
▁▂━▂🬭🬭🭗 🬁🬭🬭▂▁━▂▁
|
||||
🬂🬂🮂━🮂▔ ▔🮂━🮂🬂🬂🬿
|
||||
🭄🬨▍ 🬜🮂▔ ▁▂▂🬭🬭▂▂▁ ▔🮂🬪 🮈🬕
|
||||
🭄🭙▐▎ 🭃██████████🭎 🭢🮇▌🭤
|
||||
🭄🭙 ▐🭄🭙 🭋█████🭜█████🭀 🭤🭏▌ 🭤🭏
|
||||
🭗 🮉🭛 🭃███🭝🭙 🭥🭒███🭎 🭦▋ 🭢
|
||||
▟🬮━🭷🭘 🭋████▄▂ ▂▄████🭀 🭣━🬯🭏
|
||||
🭕╾🭺🬽 🭃██🭡 🭖██🭐 🭈╼🬡🭠
|
||||
🬼 🮉🭀 🭋███΄ 🭤███🭀 🭋▊ 🭇
|
||||
🬾 ▐🬾▁▁ 🭃██ ██🭐 ▁▁🭉🭫▌ 🭉🭠
|
||||
🬾🮈▎ ▔🮂🬂▀🬎🬎 🮅🬎▀🬂🮂▔ 🮇▌🭉
|
||||
🭿▍ ▂▁ ▁▂🬜΄🮈🬲
|
||||
🭥🬭🬭▂▁━▂▁ ▁▂━▂🬭🬭🭚
|
||||
▔⎺━▔🮂🬂🬂🬼 🭇🬂🬂🮂▔━⎺▔
|
||||
⠈🮂🭷╾🭄╼🬂🮂΄
|
||||
@@ -0,0 +1,18 @@
|
||||
#####
|
||||
#####
|
||||
#####
|
||||
######
|
||||
######
|
||||
#####
|
||||
##### #####
|
||||
###### #####
|
||||
###### #####
|
||||
###### ######
|
||||
##### ######
|
||||
##### #####
|
||||
#####
|
||||
######
|
||||
######
|
||||
######
|
||||
#####
|
||||
#####
|
||||
+33
-18
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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"},
|
||||
}))
|
||||
};
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"},
|
||||
}))
|
||||
};
|
||||
|
||||
|
||||
@@ -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"},
|
||||
}))
|
||||
};
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user