diff --git a/.codespellrc b/.codespellrc index 48fa44238a..54fbbaa781 100644 --- a/.codespellrc +++ b/.codespellrc @@ -1,5 +1,5 @@ [codespell] check-filenames = builtin = clear,rare,usage,informal -skip = */.git,*/cmake-build-*,*/.idea,*/completions,*/presets,*/screenshots,*/tests,*/3rdparty,*/logo/ascii,./src/detection/gpu/asahi_drm.h -ignore-words-list = iterm,compiletime,unknwn,pengwin,siduction,master,slave,sur,doas,conexant,ags,bu +skip = */.git,*/cmake-build-*,*/.idea,*/completions,*/presets,*/screenshots,*/tests,*/3rdparty,*/logo/ascii,./src/detection/gpu/asahi_drm.h,./src/detection/cpu/cpu_x86.c,./src/detection/gpu/gpu_bsddrm.c,./src/detection/displayserver/linux/wayland/*-protocol.*,./build,./build-*,./build_* +ignore-words-list = iterm,compiletime,unknwn,pengwin,siduction,master,slave,sur,doas,conexant,ags,bu,renderD,SME,Carmel,kinda diff --git a/.github/workflows/build-openbsd-amd64.yml b/.github/workflows/build-openbsd-amd64.yml index cae4cbb231..3c29dbaba7 100644 --- a/.github/workflows/build-openbsd-amd64.yml +++ b/.github/workflows/build-openbsd-amd64.yml @@ -20,12 +20,12 @@ jobs: architecture: x86-64 cpu_count: 4 shell: bash - version: '7.8' + version: '7.9' environment_variables: 'CMAKE_BUILD_TYPE' run: | uname -a sudo pkg_add -u - sudo pkg_add -r llvm-21.1.2p0 cmake git wayland vulkan-headers vulkan-loader glib2 dconf dbus sqlite3 imagemagick chafa lua-5.4.7 # pkg-config is preinstalled + sudo pkg_add -r llvm-21.1.8p4 cmake git wayland vulkan-headers vulkan-loader glib2 dconf dbus sqlite3 imagemagick chafa lua-5.4.8p0 # pkg-config is preinstalled CC=clang-21 cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On . cmake --build . --target package --verbose -j4 ./fastfetch --list-features diff --git a/.github/workflows/build-spellcheck.yml b/.github/workflows/build-spellcheck.yml index ca675285f0..7887227b8e 100644 --- a/.github/workflows/build-spellcheck.yml +++ b/.github/workflows/build-spellcheck.yml @@ -3,9 +3,6 @@ name: Reusable Spellcheck on: workflow_call: -env: - CMAKE_BUILD_TYPE: ${{ vars.CMAKE_BUILD_TYPE || 'RelWithDebInfo' }} - jobs: spellcheck: runs-on: ubuntu-latest @@ -17,8 +14,8 @@ jobs: - name: Install codespell shell: bash run: | - sudo apt-get update || true - sudo apt-get install -y codespell + pip3 install codespell + codespell --version - name: Run Spellchecker run: codespell diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fc0c432b07..248c5e4ce5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,6 +9,7 @@ jobs: uses: ./.github/workflows/build-spellcheck.yml no-features-test: + needs: spellcheck name: No-features-test permissions: security-events: write @@ -17,6 +18,7 @@ jobs: secrets: inherit linux-hosts: + needs: no-features-test name: Linux-${{ matrix.arch }} permissions: security-events: write @@ -35,6 +37,7 @@ jobs: secrets: inherit linux-i686: + needs: no-features-test name: Linux-i686 permissions: security-events: write @@ -43,6 +46,7 @@ jobs: secrets: inherit linux-armv7l: + needs: no-features-test name: Linux-armv7l permissions: security-events: write @@ -51,6 +55,7 @@ jobs: secrets: inherit linux-armv6l: + needs: no-features-test name: Linux-armv6l permissions: security-events: write @@ -59,6 +64,7 @@ jobs: secrets: inherit linux-vms: + needs: no-features-test name: Linux-${{ matrix.arch }} permissions: security-events: write @@ -75,11 +81,13 @@ jobs: secrets: inherit musl-amd64: + needs: no-features-test name: Musl-amd64 uses: ./.github/workflows/build-musl-amd64.yml secrets: inherit macos-hosts: + needs: no-features-test name: macOS-${{ matrix.arch }} permissions: security-events: write @@ -98,16 +106,19 @@ jobs: secrets: inherit omnios-amd64: + needs: no-features-test name: OmniOS-amd64 uses: ./.github/workflows/build-omnios-amd64.yml secrets: inherit solaris-amd64: + needs: no-features-test name: Solaris-amd64 uses: ./.github/workflows/build-solaris-amd64.yml secrets: inherit freebsd-amd64: + needs: no-features-test name: FreeBSD-amd64 permissions: security-events: write @@ -116,6 +127,7 @@ jobs: secrets: inherit openbsd-amd64: + needs: no-features-test name: OpenBSD-amd64 permissions: security-events: write @@ -124,6 +136,7 @@ jobs: secrets: inherit netbsd-amd64: + needs: no-features-test name: NetBSD-amd64 permissions: security-events: write @@ -132,6 +145,7 @@ jobs: secrets: inherit dragonfly-amd64: + needs: no-features-test name: DragonFly-amd64 permissions: security-events: write @@ -140,6 +154,7 @@ jobs: secrets: inherit haiku-amd64: + needs: no-features-test name: Haiku-amd64 permissions: security-events: write @@ -148,6 +163,7 @@ jobs: secrets: inherit windows-hosts: + needs: no-features-test name: Windows-${{ matrix.arch }} permissions: security-events: write diff --git a/.gitignore b/.gitignore index 35828e8701..db85643822 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,10 @@ -build/ -.vs/ -.vscode/ -.cache/ -.kdev4/ +/build/ +/build_*/ +/build-*/ +/.vs/ +/.vscode/ +/.cache/ +/.kdev4/ .DS_Store cscope.* tags diff --git a/CHANGELOG.md b/CHANGELOG.md index 06be822ca8..625a9e012c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,47 @@ +# 2.65.0 + +Changes: +* `display.disableLinewrap` now defaults to `false`. + * This allows long lines to wrap instead of being truncated, preventing confusion for new users. + * Wrapped lines may overlap with the image logo. Users who prefer the old behavior can set `display.disableLinewrap: true` in their config file or use `--disable-linewrap true` on the command line. +* Reorders package manager variables in custom format strings, moving aggregate variables (e.g., `all`, `brew-all`, `flatpak-all`) to the end. (Packages) + * This is a breaking change for users relying on numeric placeholders (e.g., `{1}`). Numeric placeholders are a long-deprecated feature; named placeholders (e.g., `{pacman}`) are always preferred and future-proof. +* Enables `showPeCoreCount` by default to better display hybrid-architecture core counts. (CPU) +* No longer accepts `chafa` options in config files if `chafa` support was disabled at compile time. (Logo) + * This may affect users who generated their config files using `fastfetch --gen-full-config`. To resolve this, simply remove the `chafa` section from the config file. + +Features: +* Adds detection for CPU code names (e.g., "Alder Lake", "Zen 4") and manufacturing technologies (e.g., "Intel 7", "TSMC N4") on x86 processors. (#1501, CPU, X86) + * These can be used in custom formats via `{code-name}` and `{technology}`. +* Adds PCIe link speed detection (current and max generation & lanes) for GPUs on Linux and Windows. + * These can be used in custom formats via `{pcie-max-speed}` and `{pcie-curr-speed}`. +* Adds HDR display detection via the `wp-color-management-v1` Wayland protocol. (#2356, Display, Linux) + * Previously, HDR detection was only supported on KDE Plasma. +* Adds the `egl-ext` detection method, which uses `EGL_EXT_device_enumeration` for GPU enumeration. (GPU) +* Adds terminal version and font detection for `kmscon`. (#2393, Terminal / TerminalFont, Linux) +* Adds the currently-in-beta code name "Golden Gate" for macOS 27. (OS, macOS) +* Adds WPA version detection on FreeBSD. (Wifi, FreeBSD) +* Adds package manager support for `porg` (#2405) and `install-release` (#2342). (Packages, Linux) +* Adds Weston version detection. (WM, Linux) +* Improves the core type (P-Core/E-Core) fetching mechanism on Windows by using `EfficiencyClass` instead of legacy frequency inference. (CPU, Windows) +* Improves display detection compatibility with KDE 6.7. (Display, Linux) +* Improves display serial number detection, now preferring alphanumeric serial numbers when available. (Display) + * This can be used in custom formats via `{serial}`. +* Improves the performance of `emerge` package manager detection. (#2406, Packages, Linux) +* Improves error messages for config file parsing errors. +* Improves reliability of the `Codec` module on Linux (Codec, Linux) + * Adds `va-x11` backend for VA-API and VDPAU, which is used if `va-drm` backend fails to initialize. + * Fixes an issue where the Codec module incorrectly reports no results when the `codec.showType` option is set. + +Bugfixes: +* Fixes physical core detection on non-x86 architectures and simplifies the frequency detection code. (CPU, Linux) +* Fixes console mode and output code page initialization issues when running `fastfetch` in `Conhost`. (#2383, Windows) +* Fixes public IP detection randomly failing on Linux. (#2401, PublicIP, Linux) +* Fixes several memory leaks. + +Logos: +* Adds Zerene OS. (#2404) + # 2.64.2 Bugfixes: diff --git a/CMakeLists.txt b/CMakeLists.txt index c0211aeda7..ee3dc159e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url project(fastfetch - VERSION 2.64.2 + VERSION 2.65.0 LANGUAGES C DESCRIPTION "Fast neofetch-like system information tool" HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch" @@ -63,6 +63,13 @@ endif() include(CheckIncludeFile) +if(LINUX) + CHECK_INCLUDE_FILE("linux/version.h" HAVE_LINUX_VERSION_H) + if(NOT HAVE_LINUX_VERSION_H) + message(FATAL_ERROR "Linux headers (linux/version.h) not found! Please install linux-headers package.") + endif() +endif() + ##################### # Configure options # ##################### @@ -70,13 +77,13 @@ include(CheckIncludeFile) include(CMakeDependentOption) cmake_dependent_option(ENABLE_VULKAN "Enable vulkan" ON "LINUX OR APPLE OR FreeBSD OR OpenBSD OR NetBSD OR WIN32 OR ANDROID OR SunOS OR Haiku OR GNU" OFF) -cmake_dependent_option(ENABLE_WAYLAND "Enable wayland-client" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR GNU" OFF) +cmake_dependent_option(ENABLE_WAYLAND "Enable wayland-client" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD" OFF) cmake_dependent_option(ENABLE_XCB_RANDR "Enable xcb-randr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR GNU" OFF) cmake_dependent_option(ENABLE_XRANDR "Enable xrandr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR GNU" OFF) cmake_dependent_option(ENABLE_DRM "Enable libdrm" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF) -cmake_dependent_option(ENABLE_VA "Enable libva" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF) +cmake_dependent_option(ENABLE_VADRM "Enable libva-drm" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF) +cmake_dependent_option(ENABLE_VAX11 "Enable libva-x11" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF) cmake_dependent_option(ENABLE_VDPAU "Enable vdpau" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF) -cmake_dependent_option(ENABLE_DRM_AMDGPU "Enable libdrm_amdgpu" ON "LINUX OR FreeBSD OR GNU" OFF) cmake_dependent_option(ENABLE_GIO "Enable gio-2.0" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR GNU" OFF) cmake_dependent_option(ENABLE_DCONF "Enable dconf" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR GNU" OFF) cmake_dependent_option(ENABLE_EET "Enable eet" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR GNU" OFF) @@ -134,25 +141,10 @@ if(NOT BINARY_LINK_TYPE IN_LIST BINARY_LINK_TYPE_OPTIONS) message(FATAL_ERROR "BINARY_LINK_TYPE must be one of ${BINARY_LINK_TYPE_OPTIONS}") endif() -set(PACKAGE_MANAGERS - AM APK APPIMAGE - BREW - CARDS CHOCO - DPKG - EMERGE EOPKG - FLATPAK - GUIX - HPKG - KISS - LINGLONG LPKG LPKGBUILD - MACPORTS MOSS MPORT - NIX - OPKG - PACMAN PACSTALL PALUDIS PISI PKG PKGSRC PKGTOOL - RPM - SCOOP SNAP SOAR SORCERY - WINGET - XBPS) +file(READ "${CMAKE_CURRENT_SOURCE_DIR}/src/modules/packages/option.h" PACKAGE_MANAGERS) +string(REGEX MATCHALL "FF_PACKAGES_FLAG_[A-Z]+_BIT" PACKAGE_MANAGERS "${PACKAGE_MANAGERS}") +string(REGEX REPLACE "FF_PACKAGES_FLAG_([A-Z]+)_BIT" "\\1" PACKAGE_MANAGERS "${PACKAGE_MANAGERS}") +list(SORT PACKAGE_MANAGERS) foreach(package_manager ${PACKAGE_MANAGERS}) if(package_manager STREQUAL "WINGET") option(PACKAGES_DISABLE_${package_manager} "Disable ${package_manager} package manager detection by default" ON) @@ -327,7 +319,7 @@ if(Python_FOUND) endif() else() message(WARNING "Python3 is not found, 'help.json' will not be minified") - file(READ "doc/help.json" DATATEXT_JSON_HELP) + file(READ "${CMAKE_CURRENT_SOURCE_DIR}/doc/help.json" DATATEXT_JSON_HELP) endif() if(ENABLE_EMBEDDED_PCIIDS AND NOT EXISTS "${PROJECT_BINARY_DIR}/fastfetch_pciids.c.inc") @@ -447,6 +439,7 @@ set(LIBFASTFETCH_SRC src/detection/codec/codec.c src/detection/codec/codec_vulkan.c src/detection/cpu/cpu.c + src/detection/cpu/cpu_x86.c src/detection/cpuusage/cpuusage.c src/detection/command/command.c src/detection/disk/disk.c @@ -591,11 +584,10 @@ if(LINUX) src/detection/displayserver/linux/drm.c src/detection/displayserver/linux/wayland/wayland.c src/detection/displayserver/linux/wayland/global-output.c - src/detection/displayserver/linux/wayland/zwlr-output.c + src/detection/displayserver/linux/wayland/wl-output-protocol.c + src/detection/displayserver/linux/wayland/wp-color-management-v1-protocol.c src/detection/displayserver/linux/wayland/kde-output.c - src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-protocol.c src/detection/displayserver/linux/wayland/kde-output-device-v2-protocol.c - src/detection/displayserver/linux/wayland/kde-output-order-v1-protocol.c src/detection/displayserver/linux/wayland/xdg-output-unstable-v1-protocol.c src/detection/displayserver/linux/wmde.c src/detection/displayserver/linux/xcb.c @@ -752,11 +744,10 @@ elseif(FreeBSD) src/detection/displayserver/linux/drm.c src/detection/displayserver/linux/wayland/wayland.c src/detection/displayserver/linux/wayland/global-output.c - src/detection/displayserver/linux/wayland/zwlr-output.c src/detection/displayserver/linux/wayland/kde-output.c - src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-protocol.c + src/detection/displayserver/linux/wayland/wl-output-protocol.c + src/detection/displayserver/linux/wayland/wp-color-management-v1-protocol.c src/detection/displayserver/linux/wayland/kde-output-device-v2-protocol.c - src/detection/displayserver/linux/wayland/kde-output-order-v1-protocol.c src/detection/displayserver/linux/wayland/xdg-output-unstable-v1-protocol.c src/detection/displayserver/linux/wmde.c src/detection/displayserver/linux/xcb.c @@ -765,6 +756,7 @@ elseif(FreeBSD) src/detection/gpu/gpu_bsd.c src/detection/gpu/gpu_drm.c src/detection/gpu/gpu_pci.c + src/detection/gpu/gpu_bsddrm.c src/detection/gtk_qt/gtk.c src/detection/host/host_bsd.c src/detection/lm/lm_linux.c @@ -847,11 +839,10 @@ elseif(NetBSD) src/detection/displayserver/linux/drm.c src/detection/displayserver/linux/wayland/wayland.c src/detection/displayserver/linux/wayland/global-output.c - src/detection/displayserver/linux/wayland/zwlr-output.c src/detection/displayserver/linux/wayland/kde-output.c - src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-protocol.c + src/detection/displayserver/linux/wayland/wl-output-protocol.c + src/detection/displayserver/linux/wayland/wp-color-management-v1-protocol.c src/detection/displayserver/linux/wayland/kde-output-device-v2-protocol.c - src/detection/displayserver/linux/wayland/kde-output-order-v1-protocol.c src/detection/displayserver/linux/wayland/xdg-output-unstable-v1-protocol.c src/detection/displayserver/linux/wmde.c src/detection/displayserver/linux/xcb.c @@ -932,11 +923,10 @@ elseif(OpenBSD) src/detection/displayserver/linux/drm.c src/detection/displayserver/linux/wayland/wayland.c src/detection/displayserver/linux/wayland/global-output.c - src/detection/displayserver/linux/wayland/zwlr-output.c src/detection/displayserver/linux/wayland/kde-output.c - src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-protocol.c + src/detection/displayserver/linux/wayland/wl-output-protocol.c + src/detection/displayserver/linux/wayland/wp-color-management-v1-protocol.c src/detection/displayserver/linux/wayland/kde-output-device-v2-protocol.c - src/detection/displayserver/linux/wayland/kde-output-order-v1-protocol.c src/detection/displayserver/linux/wayland/xdg-output-unstable-v1-protocol.c src/detection/displayserver/linux/wmde.c src/detection/displayserver/linux/xcb.c @@ -944,6 +934,8 @@ elseif(OpenBSD) src/detection/font/font_linux.c src/detection/gpu/gpu_pci.c src/detection/gpu/gpu_obsd.c + src/detection/gpu/gpu_drm.c + src/detection/gpu/gpu_bsddrm.c src/detection/gtk_qt/gtk.c src/detection/host/host_obsd.c src/detection/lm/lm_nosupport.c @@ -1175,11 +1167,10 @@ elseif(SunOS) src/detection/displayserver/linux/drm.c src/detection/displayserver/linux/wayland/wayland.c src/detection/displayserver/linux/wayland/global-output.c - src/detection/displayserver/linux/wayland/zwlr-output.c src/detection/displayserver/linux/wayland/kde-output.c - src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-protocol.c + src/detection/displayserver/linux/wayland/wl-output-protocol.c + src/detection/displayserver/linux/wayland/wp-color-management-v1-protocol.c src/detection/displayserver/linux/wayland/kde-output-device-v2-protocol.c - src/detection/displayserver/linux/wayland/kde-output-order-v1-protocol.c src/detection/displayserver/linux/wayland/xdg-output-unstable-v1-protocol.c src/detection/displayserver/linux/wmde.c src/detection/displayserver/linux/xcb.c @@ -1325,12 +1316,9 @@ elseif(GNU) src/detection/physicalmemory/physicalmemory_nosupport.c src/detection/diskio/diskio_nosupport.c src/detection/displayserver/linux/displayserver_linux.c + src/detection/displayserver/linux/wayland/wayland.c src/detection/displayserver/linux/common.c src/detection/displayserver/linux/drm.c - src/detection/displayserver/linux/wayland/wayland.c - src/detection/displayserver/linux/wayland/global-output.c - src/detection/displayserver/linux/wayland/zwlr-output.c - src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-protocol.c src/detection/displayserver/linux/wmde.c src/detection/displayserver/linux/xcb.c src/detection/displayserver/linux/xlib.c @@ -1576,24 +1564,24 @@ endif() if(NOT "${CUSTOM_PCI_IDS_PATH}" STREQUAL "") message(STATUS "Custom file path of pci.ids: ${CUSTOM_PCI_IDS_PATH}") - target_compile_definitions(libfastfetch PRIVATE FF_CUSTOM_PCI_IDS_PATH=${CUSTOM_PCI_IDS_PATH}) + target_compile_definitions(libfastfetch PUBLIC FF_CUSTOM_PCI_IDS_PATH=${CUSTOM_PCI_IDS_PATH}) endif() if(NOT "${CUSTOM_AMDGPU_IDS_PATH}" STREQUAL "") message(STATUS "Custom file path of amdgpu.ids: ${CUSTOM_AMDGPU_IDS_PATH}") - target_compile_definitions(libfastfetch PRIVATE FF_CUSTOM_AMDGPU_IDS_PATH=${CUSTOM_AMDGPU_IDS_PATH}) + target_compile_definitions(libfastfetch PUBLIC FF_CUSTOM_AMDGPU_IDS_PATH=${CUSTOM_AMDGPU_IDS_PATH}) endif() if(NOT "${CUSTOM_OS_RELEASE_PATH}" STREQUAL "") message(STATUS "Custom file path of os_release: ${CUSTOM_OS_RELEASE_PATH}") - target_compile_definitions(libfastfetch PRIVATE FF_CUSTOM_OS_RELEASE_PATH=${CUSTOM_OS_RELEASE_PATH}) + target_compile_definitions(libfastfetch PUBLIC FF_CUSTOM_OS_RELEASE_PATH=${CUSTOM_OS_RELEASE_PATH}) endif() if(NOT "${CUSTOM_LSB_RELEASE_PATH}" STREQUAL "") message(STATUS "Custom file path of lsb_release: ${CUSTOM_LSB_RELEASE_PATH}") - target_compile_definitions(libfastfetch PRIVATE FF_CUSTOM_LSB_RELEASE_PATH=${CUSTOM_LSB_RELEASE_PATH}) + target_compile_definitions(libfastfetch PUBLIC FF_CUSTOM_LSB_RELEASE_PATH=${CUSTOM_LSB_RELEASE_PATH}) endif() if(NOT BINARY_LINK_TYPE STREQUAL "dlopen") message(STATUS "Enabling custom link type: ${BINARY_LINK_TYPE}") - target_compile_definitions(libfastfetch PRIVATE FF_DISABLE_DLOPEN=1) + target_compile_definitions(libfastfetch PUBLIC FF_DISABLE_DLOPEN=1) if(NOT WIN32) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--copy-dt-needed-entries") endif() @@ -1659,18 +1647,18 @@ function(ff_lib_enable VARNAME PKGCONFIG_NAMES CMAKE_NAME) # [CMAKE_TARGET_NAME] message(STATUS "Library: found ${VARNAME} by ${${VARNAME}_FOUND}") - target_compile_definitions(libfastfetch PRIVATE FF_HAVE_${VARNAME}=1) + target_compile_definitions(libfastfetch PUBLIC FF_HAVE_${VARNAME}=1) target_include_directories(libfastfetch PRIVATE ${${VARNAME}_INCLUDE_DIRS}) if(NOT BINARY_LINK_TYPE STREQUAL "dlopen") - target_link_directories(libfastfetch PUBLIC ${${VARNAME}_LIBRARY_DIRS}) + target_link_directories(libfastfetch PRIVATE ${${VARNAME}_LIBRARY_DIRS}) target_link_libraries(libfastfetch PRIVATE ${${VARNAME}_LIBRARIES}) endif() foreach(FLAG ${${VARNAME}_CFLAGS_OTHER}) if(FLAG MATCHES "-D.*") string(SUBSTRING ${FLAG} 2 -1 FLAG) - target_compile_definitions(libfastfetch PRIVATE ${FLAG}) + target_compile_definitions(libfastfetch PUBLIC ${FLAG}) endif() endforeach() endfunction() @@ -1695,18 +1683,18 @@ ff_lib_enable(DRM "libdrm" "Libdrm" ) -ff_lib_enable(VA +ff_lib_enable(VADRM "libva-drm" "Libva-drm" ) +ff_lib_enable(VAX11 + "libva-x11" + "Libva-x11" +) ff_lib_enable(VDPAU "vdpau" "vdpau" ) -ff_lib_enable(DRM_AMDGPU - "libdrm_amdgpu" - "Libdrm_Amdgpu" -) ff_lib_enable(GIO "gio-2.0" "GIO" @@ -1800,8 +1788,8 @@ if(ENABLE_LUA) message(STATUS "Library: Lua version ${Lua_VERSION} is not supported, requires 5.3-5.5") unset(Lua_FOUND) else() - target_compile_definitions(libfastfetch PRIVATE FF_HAVE_LUA=1) - target_include_directories(libfastfetch PRIVATE ${LUA_INCLUDE_DIR}) + target_compile_definitions(libfastfetch PUBLIC FF_HAVE_LUA=1) + target_include_directories(libfastfetch PUBLIC ${LUA_INCLUDE_DIR}) if(NOT BINARY_LINK_TYPE STREQUAL "dlopen") target_link_libraries(libfastfetch PRIVATE ${LUA_LIBRARIES}) @@ -1814,20 +1802,20 @@ if(ENABLE_LUA) endif() if(ENABLE_THREADS) - target_compile_definitions(libfastfetch PRIVATE FF_HAVE_THREADS=1) + target_compile_definitions(libfastfetch PUBLIC FF_HAVE_THREADS=1) if(CMAKE_USE_PTHREADS_INIT) #Threads::Threads is not set for WIN32 target_link_libraries(libfastfetch PRIVATE Threads::Threads) endif() endif() if(ENABLE_EMBEDDED_PCIIDS) - target_compile_definitions(libfastfetch PRIVATE FF_HAVE_EMBEDDED_PCIIDS=1) + target_compile_definitions(libfastfetch PUBLIC FF_HAVE_EMBEDDED_PCIIDS=1) endif() if(ENABLE_EMBEDDED_AMDGPUIDS) - target_compile_definitions(libfastfetch PRIVATE FF_HAVE_EMBEDDED_AMDGPUIDS=1) + target_compile_definitions(libfastfetch PUBLIC FF_HAVE_EMBEDDED_AMDGPUIDS=1) endif() if(ENABLE_LIBZFS) - target_compile_definitions(libfastfetch PRIVATE FF_HAVE_LIBZFS=1) + target_compile_definitions(libfastfetch PUBLIC FF_HAVE_LIBZFS=1) if(NOT BINARY_LINK_TYPE STREQUAL "dlopen") target_link_libraries(libfastfetch @@ -1984,7 +1972,7 @@ target_link_libraries(libfastfetch PRIVATE ${CMAKE_DL_LIBS} ) -target_compile_options(libfastfetch PRIVATE +target_compile_options(libfastfetch PUBLIC $<$:-fno-exceptions -fno-rtti>) if(FreeBSD) @@ -1993,18 +1981,18 @@ endif() if(LINUX OR FreeBSD OR OpenBSD OR NetBSD) CHECK_INCLUDE_FILE("linux/videodev2.h" HAVE_LINUX_VIDEODEV2) if(HAVE_LINUX_VIDEODEV2) - target_compile_definitions(libfastfetch PRIVATE FF_HAVE_LINUX_VIDEODEV2=1) + target_compile_definitions(libfastfetch PUBLIC FF_HAVE_LINUX_VIDEODEV2=1) endif() endif() if(NOT WIN32) CHECK_INCLUDE_FILE("utmpx.h" HAVE_UTMPX) if(HAVE_UTMPX) - target_compile_definitions(libfastfetch PRIVATE FF_HAVE_UTMPX=1) + target_compile_definitions(libfastfetch PUBLIC FF_HAVE_UTMPX=1) endif() if(ENABLE_WORDEXP) CHECK_INCLUDE_FILE("wordexp.h" HAVE_WORDEXP) if(HAVE_WORDEXP) - target_compile_definitions(libfastfetch PRIVATE FF_HAVE_WORDEXP=1) + target_compile_definitions(libfastfetch PUBLIC FF_HAVE_WORDEXP=1) message(STATUS "wordexp.h found, wordexp support enabled") else() set(ENABLE_WORDEXP OFF) @@ -2016,19 +2004,19 @@ if(NOT WIN32) if(ENABLE_THREADS AND CMAKE_USE_PTHREADS_INIT) CHECK_INCLUDE_FILE("pthread_np.h" HAVE_PTHREAD_NP) if(HAVE_PTHREAD_NP) - target_compile_definitions(libfastfetch PRIVATE FF_HAVE_PTHREAD_NP=1) + target_compile_definitions(libfastfetch PUBLIC FF_HAVE_PTHREAD_NP=1) set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} pthread_np.h) endif() set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} Threads::Threads) check_function_exists("pthread_timedjoin_np" HAVE_TIMEDJOIN_NP) if(HAVE_TIMEDJOIN_NP) - target_compile_definitions(libfastfetch PRIVATE FF_HAVE_TIMEDJOIN_NP=1) + target_compile_definitions(libfastfetch PUBLIC FF_HAVE_TIMEDJOIN_NP=1) else() message(WARNING "pthread_timedjoin_np was not found; networking timeout will not work") endif() endif() elseif(HAVE_WINRT) - target_compile_definitions(libfastfetch PRIVATE FF_HAVE_WINRT=1) + target_compile_definitions(libfastfetch PUBLIC FF_HAVE_WINRT=1) endif() set(PACKAGES_DISABLE_LIST "") @@ -2045,9 +2033,9 @@ else() list(TRANSFORM PACKAGES_DISABLE_LIST APPEND "_BIT") list(JOIN PACKAGES_DISABLE_LIST " | " PACKAGES_DISABLE_LIST) endif() -target_compile_definitions(libfastfetch PRIVATE "FF_PACKAGES_DISABLE_LIST=${PACKAGES_DISABLE_LIST}") +target_compile_definitions(libfastfetch PUBLIC "FF_PACKAGES_DISABLE_LIST=${PACKAGES_DISABLE_LIST}") if(PACKAGES_REMOVE_DISABLED) - target_compile_definitions(libfastfetch PRIVATE FF_PACKAGES_REMOVE_DISABLED=1) + target_compile_definitions(libfastfetch PUBLIC FF_PACKAGES_REMOVE_DISABLED=1) endif() ###################### diff --git a/debian/changelog.tpl b/debian/changelog.tpl index a8ddebdebb..6c93660ac0 100644 --- a/debian/changelog.tpl +++ b/debian/changelog.tpl @@ -1,3 +1,9 @@ +fastfetch (2.64.2~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium + + * Update to 2.64.2 + + -- Carter Li Mon, 08 Jun 2026 15:45:11 +0800 + fastfetch (2.63.1~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium * Update to 2.63.1 diff --git a/doc/json_schema.json b/doc/json_schema.json index 2243fb6f59..e9271b2ff7 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -322,7 +322,7 @@ "type": "string" }, "cpuFormat": { - "description": "Output format for the `CPU` module. See Wiki for formatting syntax\n 1. {name}: Name\n 2. {vendor}: Vendor\n 3. {cores-physical}: Physical core count\n 4. {cores-logical}: Logical core count\n 5. {cores-online}: Online core count\n 6. {freq-base}: Base frequency (formatted)\n 7. {freq-max}: Max frequency (formatted)\n 8. {temperature}: Temperature (formatted)\n 9. {core-types}: Logical core count grouped by frequency\n 10. {packages}: Processor package count\n 11. {march}: CPU microarchitecture\n 12. {numa-nodes}: NUMA node count", + "description": "Output format for the `CPU` module. See Wiki for formatting syntax\n 1. {name}: Name\n 2. {vendor}: Vendor\n 3. {cores-physical}: Physical core count\n 4. {cores-logical}: Logical core count\n 5. {cores-online}: Online core count\n 6. {freq-base}: Base frequency (formatted)\n 7. {freq-max}: Max frequency (formatted)\n 8. {temperature}: Temperature (formatted)\n 9. {core-types}: Logical core count grouped by frequency\n 10. {packages}: Processor package count\n 11. {march}: CPU microarchitecture\n 12. {numa-nodes}: NUMA node count\n 13. {code-name}: CPU code name\n 14. {technology}: CPU technology", "type": "string" }, "cpucacheFormat": { @@ -374,7 +374,7 @@ "type": "string" }, "gpuFormat": { - "description": "Output format for the `GPU` module. See Wiki for formatting syntax\n 1. {vendor}: GPU vendor\n 2. {name}: GPU name\n 3. {driver}: GPU driver\n 4. {temperature}: GPU temperature\n 5. {core-count}: GPU core count\n 6. {type}: GPU type\n 7. {dedicated-total}: GPU total dedicated memory\n 8. {dedicated-used}: GPU used dedicated memory\n 9. {shared-total}: GPU total shared memory\n 10. {shared-used}: GPU used shared memory\n 11. {platform-api}: The platform API used when detecting the GPU\n 12. {frequency}: Current frequency in GHz\n 13. {index}: GPU vendor specific index\n 14. {dedicated-percentage-num}: Dedicated memory usage percentage num\n 15. {dedicated-percentage-bar}: Dedicated memory usage percentage bar\n 16. {shared-percentage-num}: Shared memory usage percentage num\n 17. {shared-percentage-bar}: Shared memory usage percentage bar\n 18. {core-usage-num}: Core usage percentage num\n 19. {core-usage-bar}: Core usage percentage bar\n 20. {memory-type}: Memory type (Windows only)", + "description": "Output format for the `GPU` module. See Wiki for formatting syntax\n 1. {vendor}: GPU vendor\n 2. {name}: GPU name\n 3. {driver}: GPU driver\n 4. {temperature}: GPU temperature\n 5. {core-count}: GPU core count\n 6. {type}: GPU type\n 7. {dedicated-total}: GPU total dedicated memory\n 8. {dedicated-used}: GPU used dedicated memory\n 9. {shared-total}: GPU total shared memory\n 10. {shared-used}: GPU used shared memory\n 11. {platform-api}: The platform API used when detecting the GPU\n 12. {frequency}: Current frequency in GHz\n 13. {index}: GPU vendor specific index\n 14. {dedicated-percentage-num}: Dedicated memory usage percentage num\n 15. {dedicated-percentage-bar}: Dedicated memory usage percentage bar\n 16. {shared-percentage-num}: Shared memory usage percentage num\n 17. {shared-percentage-bar}: Shared memory usage percentage bar\n 18. {core-usage-num}: Core usage percentage num\n 19. {core-usage-bar}: Core usage percentage bar\n 20. {memory-type}: Memory type (Windows only)\n 21. {pcie-max-speed}: PCIe maximum speed in gen and lanes\n 22. {pcie-curr-speed}: PCIe current speed in gen and lanes", "type": "string" }, "hostFormat": { @@ -446,7 +446,7 @@ "type": "string" }, "packagesFormat": { - "description": "Output format for the `Packages` module. See Wiki for formatting syntax\n 1. {all}: Number of all packages\n 2. {am-system}: Number of am-system packages\n 3. {am-user}: Number of am-user (aka appman) packages\n 4. {appimage}: Number of appimage packages\n 5. {apk}: Number of apk packages\n 6. {brew}: Number of brew packages\n 7. {brew-all}: Total number of all brew packages\n 8. {brew-cask}: Number of brew-cask packages\n 9. {cards}: Number of cards packages\n 10. {choco}: Number of choco packages\n 11. {dpkg}: Number of dpkg packages\n 12. {emerge}: Number of emerge packages\n 13. {eopkg}: Number of eopkg packages\n 14. {flatpak-all}: Total number of all flatpak app packages\n 15. {flatpak-system}: Number of flatpak-system app packages\n 16. {flatpak-user}: Number of flatpak-user app packages\n 17. {guix-all}: Total number of all guix packages\n 18. {guix-home}: Number of guix-home packages\n 19. {guix-system}: Number of guix-system packages\n 20. {guix-user}: Number of guix-user packages\n 21. {hpkg-all}: Total number of all hpkg packages\n 22. {hpkg-system}: Number of hpkg-system packages\n 23. {hpkg-user}: Number of hpkg-user packages\n 24. {kiss}: Number of kiss packages\n 25. {linglong}: Number of linglong packages\n 26. {lpkg}: Number of lpkg packages\n 27. {lpkgbuild}: Number of lpkgbuild packages\n 28. {macports}: Number of macports packages\n 29. {mport}: Number of mport packages\n 30. {moss}: Number of moss packages\n 31. {nix-all}: Total number of all nix packages\n 32. {nix-default}: Number of nix-default packages\n 33. {nix-system}: Number of nix-system packages\n 34. {nix-user}: Number of nix-user packages\n 35. {opkg}: Number of opkg packages\n 36. {pacman}: Number of pacman packages\n 37. {pacman-branch}: Pacman branch on manjaro\n 38. {pacstall}: Number of pacstall packages\n 39. {paludis}: Number of paludis packages\n 40. {pisi}: Number of pisi packages\n 41. {pkg}: Number of pkg packages\n 42. {pkgsrc}: Number of pkgsrc packages\n 43. {pkgtool}: Number of pkgtool packages\n 44. {rpm}: Number of rpm packages\n 45. {scoop-global}: Number of scoop-global packages\n 46. {scoop-user}: Number of scoop-user packages\n 47. {snap}: Number of snap packages\n 48. {soar}: Number of soar packages\n 49. {sorcery}: Number of sorcery packages\n 50. {winget}: Number of winget packages\n 51. {xbps}: Number of xbps packages", + "description": "Output format for the `Packages` module. See Wiki for formatting syntax\n 1. {am-system}: Number of am-system packages\n 2. {am-user}: Number of am-user (aka appman) packages\n 3. {appimage}: Number of appimage packages\n 4. {apk}: Number of apk packages\n 5. {brew}: Number of brew packages\n 6. {brew-cask}: Number of brew-cask packages\n 7. {cards}: Number of cards packages\n 8. {choco}: Number of choco packages\n 9. {dpkg}: Number of dpkg packages\n 10. {emerge}: Number of emerge packages\n 11. {eopkg}: Number of eopkg packages\n 12. {flatpak-system}: Number of flatpak-system app packages\n 13. {flatpak-user}: Number of flatpak-user app packages\n 14. {guix-home}: Number of guix-home packages\n 15. {guix-system}: Number of guix-system packages\n 16. {guix-user}: Number of guix-user packages\n 17. {hpkg-system}: Number of hpkg-system packages\n 18. {hpkg-user}: Number of hpkg-user packages\n 19. {install-release}: Number of install-release packages\n 20. {kiss}: Number of kiss packages\n 21. {linglong}: Number of linglong packages\n 22. {lpkg}: Number of lpkg packages\n 23. {lpkgbuild}: Number of lpkgbuild packages\n 24. {macports}: Number of macports packages\n 25. {mport}: Number of mport packages\n 26. {moss}: Number of moss packages\n 27. {nix-default}: Number of nix-default packages\n 28. {nix-system}: Number of nix-system packages\n 29. {nix-user}: Number of nix-user packages\n 30. {opkg}: Number of opkg packages\n 31. {pacman}: Number of pacman packages\n 32. {pacman-branch}: Pacman branch on manjaro\n 33. {pacstall}: Number of pacstall packages\n 34. {paludis}: Number of paludis packages\n 35. {pisi}: Number of pisi packages\n 36. {pkg}: Number of pkg packages\n 37. {pkgsrc}: Number of pkgsrc packages\n 38. {pkgtool}: Number of pkgtool packages\n 39. {porg}: Number of porg packages\n 40. {rpm}: Number of rpm packages\n 41. {scoop-global}: Number of scoop-global packages\n 42. {scoop-user}: Number of scoop-user packages\n 43. {snap}: Number of snap packages\n 44. {soar}: Number of soar packages\n 45. {sorcery}: Number of sorcery packages\n 46. {winget}: Number of winget packages\n 47. {xbps}: Number of xbps packages\n 48. {brew-all}: Total number of all brew packages\n 49. {flatpak-all}: Total number of all flatpak app packages\n 50. {guix-all}: Total number of all guix packages\n 51. {hpkg-all}: Total number of all hpkg packages\n 52. {nix-all}: Total number of all nix packages\n 53. {all}: Number of all packages", "type": "string" }, "physicaldiskFormat": { @@ -2850,6 +2850,10 @@ "const": "opencl", "description": "Use OpenCL API.\nSlow and requires proper OpenCL drivers to be installed" }, + { + "const": "egl-ext", + "description": "Use EGL_EXT_device_enumeration and EGL_EXT_device_query APIs.\nSlow and only detects GPUs that support these extensions" + }, { "const": "opengl", "description": "Use OpenGL API.\nSlow and only detects one GPU.\nUsed for OpenBSD" diff --git a/src/common/attributes.h b/src/common/attributes.h index ff1e66067b..a7b964c4d4 100644 --- a/src/common/attributes.h +++ b/src/common/attributes.h @@ -17,3 +17,4 @@ #define FF_A_PACKED __attribute__((__packed__)) #define FF_A_WEAK_IMPORT __attribute__((__weak_import__)) #define FF_A_ALWAYS_INLINE __attribute__((__always_inline__)) +#define FF_A_COLD __attribute__((__cold__)) diff --git a/src/common/debug.h b/src/common/debug.h index a378fc841b..d79c48880f 100644 --- a/src/common/debug.h +++ b/src/common/debug.h @@ -33,5 +33,6 @@ static inline const char* ffFindFileName(const char* file) { #if _WIN32 const char* ffDebugWin32Error(DWORD errorCode); const char* ffDebugNtStatus(NTSTATUS status); +const char* ffDebugConfigRet(unsigned long /*CONFIGRET*/ ret); const char* ffDebugHResult(HRESULT hr); #endif diff --git a/src/common/edidHelper.h b/src/common/edidHelper.h index dc4e4fb3a6..44065790af 100644 --- a/src/common/edidHelper.h +++ b/src/common/edidHelper.h @@ -8,6 +8,7 @@ bool ffEdidGetName(const uint8_t edid[128], FFstrbuf* name); void ffEdidGetPreferredResolutionAndRefreshRate(const uint8_t edid[128], uint32_t* width, uint32_t* height, double* refreshRate); void ffEdidGetPhysicalResolution(const uint8_t edid[128], uint32_t* width, uint32_t* height); void ffEdidGetPhysicalSize(const uint8_t edid[128], uint32_t* width, uint32_t* height); // in mm -void ffEdidGetSerialAndManufactureDate(const uint8_t edid[128], uint32_t* serial, uint16_t* year, uint16_t* week); +void ffEdidGetManufactureDate(const uint8_t edid[128], uint16_t* year, uint16_t* week); +bool ffEdidGetSerial(const uint8_t edid[128], FFstrbuf* result); bool ffEdidGetHdrCompatible(const uint8_t* edid, uint32_t length); bool ffEdidIsValid(const uint8_t edid[128], uint32_t length); diff --git a/src/common/impl/FFPlatform_unix.c b/src/common/impl/FFPlatform_unix.c index de69f6bef6..3b9c87db7e 100644 --- a/src/common/impl/FFPlatform_unix.c +++ b/src/common/impl/FFPlatform_unix.c @@ -30,7 +30,7 @@ static void getExePath(FFPlatform* platform) { char exePath[PATH_MAX]; #if defined(__linux__) || defined(__GNU__) ssize_t exePathLen = readlink("/proc/self/exe", exePath, sizeof(exePath) - 1); - if (exePathLen >= 0) { + if (exePathLen > 0) { exePath[exePathLen] = '\0'; } #elif defined(__APPLE__) @@ -128,7 +128,7 @@ static void getExePath(FFPlatform* platform) { } #elif defined(__sun) ssize_t exePathLen = readlink("/proc/self/path/a.out", exePath, sizeof(exePath) - 1); - if (exePathLen >= 0) { + if (exePathLen > 0) { exePath[exePathLen] = '\0'; } #elif defined(__HAIKU__) diff --git a/src/common/impl/debug_windows.c b/src/common/impl/debug_windows.c index fb76a659ef..a3fb7f3dc0 100644 --- a/src/common/impl/debug_windows.c +++ b/src/common/impl/debug_windows.c @@ -2,6 +2,7 @@ #include "common/windows/nt.h" #include +#include const char* ffDebugWin32Error(DWORD errorCode) { static char buffer[512]; @@ -34,6 +35,10 @@ const char* ffDebugWin32Error(DWORD errorCode) { return buffer; } +const char* ffDebugConfigRet(CONFIGRET ret) { + return ffDebugWin32Error(CM_MapCrToWin32Err(ret, ERROR_INTERNAL_ERROR)); +} + const char* ffDebugNtStatus(NTSTATUS status) { return ffDebugWin32Error(RtlNtStatusToDosError(status)); } diff --git a/src/common/impl/edidHelper.c b/src/common/impl/edidHelper.c index 1e3310e2a4..4b8f4f84dc 100644 --- a/src/common/impl/edidHelper.c +++ b/src/common/impl/edidHelper.c @@ -66,7 +66,7 @@ void ffEdidGetPhysicalSize(const uint8_t edid[128], uint32_t* width, uint32_t* h } } -void ffEdidGetSerialAndManufactureDate(const uint8_t edid[128], uint32_t* serial, uint16_t* year, uint16_t* week) { +void ffEdidGetManufactureDate(const uint8_t edid[128], uint16_t* year, uint16_t* week) { if (edid[17] > 0 && edid[17] < 0xFF) { *year = (uint16_t) (edid[17] + 1990); *week = (uint16_t) edid[16]; @@ -76,8 +76,49 @@ void ffEdidGetSerialAndManufactureDate(const uint8_t edid[128], uint32_t* serial } else { *year = *week = 0; } +} + +bool ffEdidGetSerial(const uint8_t edid[128], FFstrbuf* result) { + int descriptor_offsets[4] = {54, 72, 90, 108}; + + for (int i = 0; i < 4; i++) { + int offset = descriptor_offsets[i]; + const uint8_t* desc = edid + offset; + + if (desc[0] == 0x00 && desc[1] == 0x00) { // Monitor Descriptor + uint8_t tag = desc[3]; // Descriptor Type Tag + + if (tag == 0xFF) { // Display Product Serial Number + ffStrbufClear(result); + for (int j = 0; j < 13; j++) { + uint8_t ch = desc[5 + j]; + + if (ch == 0x0A || ch == 0x00) { + break; + } + + ffStrbufAppendC(result, (char) ch); + } - *serial = *(uint32_t*) &edid[12]; + ffStrbufTrim(result, ' '); + if (result->length > 0) { + return true; + } + } + } + } + + uint32_t int_serial = 0; + int_serial |= (uint32_t)edid[12]; + int_serial |= (uint32_t)edid[13] << 8; + int_serial |= (uint32_t)edid[14] << 16; + int_serial |= (uint32_t)edid[15] << 24; + + if (int_serial != 0 && int_serial != 0xFFFFFFFF) { + ffStrbufSetF(result, "0x%08X", int_serial); + return true; + } + return false; } bool ffEdidGetHdrCompatible(const uint8_t* edid, uint32_t length) { diff --git a/src/common/impl/init.c b/src/common/impl/init.c index f0fc0a2f32..95e6cfd766 100644 --- a/src/common/impl/init.c +++ b/src/common/impl/init.c @@ -3,6 +3,7 @@ #include "common/parsing.h" #include "common/thread.h" #include "common/textModifier.h" +#include "common/strutil.h" #include "detection/displayserver/displayserver.h" #include "detection/terminaltheme/terminaltheme.h" #include "logo/logo.h" @@ -16,6 +17,9 @@ #else #include #endif +#if __linux__ + #include +#endif FFinstance instance; // Global singleton @@ -46,10 +50,30 @@ static void defaultConfig(void) { ffOptionsInitDisplay(&instance.config.display); } +#ifdef _WIN32 +static volatile UINT oldCp = CP_UTF8; +void resetConsoleCP(void) { + if (oldCp != CP_UTF8) { + SetConsoleOutputCP(oldCp); + } +} +#endif + void ffInitInstance(void) { #ifdef _WIN32 // https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale?source=recommendat> setlocale(LC_ALL, ".UTF8"); + + HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); + DWORD mode = 0; + if (GetConsoleMode(hStdout, &mode)) { + SetConsoleMode(hStdout, mode | ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING); + oldCp = GetConsoleOutputCP(); + if (oldCp != CP_UTF8) { + SetConsoleOutputCP(CP_UTF8); + atexit(resetConsoleCP); + } + } #else // Never use `setlocale(LC_ALL, "")` setlocale(LC_TIME, ""); @@ -61,9 +85,6 @@ void ffInitInstance(void) { static volatile bool ffDisableLinewrap = false; static volatile bool ffHideCursor = false; -#ifdef _WIN32 -static volatile UINT oldCp = CP_UTF8; -#endif static void resetConsole(void) { if (ffDisableLinewrap) { @@ -80,10 +101,6 @@ static void resetConsole(void) { #if defined(_WIN32) fflush(stdout); - - if (oldCp != CP_UTF8) { - SetConsoleOutputCP(oldCp); - } #endif } @@ -111,15 +128,6 @@ void ffStart(void) { setvbuf(stdout, NULL, _IOFBF, 4096); } SetConsoleCtrlHandler(consoleHandler, TRUE); - HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); - DWORD mode = 0; - if (GetConsoleMode(hStdout, &mode)) { - SetConsoleMode(hStdout, mode | ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING); - oldCp = GetConsoleOutputCP(); - if (oldCp != CP_UTF8) { - SetConsoleOutputCP(CP_UTF8); - } - } #else if (instance.config.display.noBuffer) { setvbuf(stdout, NULL, _IONBF, 0); @@ -180,13 +188,14 @@ void ffDestroyInstance(void) { #endif #if FF_HAVE_QUICKJS #include - #define FF_STR_INDIR(x) #x - #define FF_STR(x) FF_STR_INDIR(x) #endif // Must be in a file compiled with the libfastfetch target, because the FF_HAVE* macros are not defined for the executable targets void ffListFeatures(void) { fputs( +#if __linux__ + "linux-headers " FF_STR(LINUX_VERSION_MAJOR) "." FF_STR(LINUX_VERSION_PATCHLEVEL) "." FF_STR(LINUX_VERSION_SUBLEVEL) "\n" +#endif #if FF_HAVE_THREADS "threads\n" #endif @@ -205,9 +214,6 @@ void ffListFeatures(void) { #if FF_HAVE_DRM "drm\n" #endif -#if FF_HAVE_DRM_AMDGPU - "drm_amdgpu\n" -#endif #if FF_HAVE_GIO "gio\n" #endif @@ -262,8 +268,11 @@ void ffListFeatures(void) { #if FF_HAVE_LIBZFS "libzfs\n" #endif -#if FF_HAVE_VA - "va\n" +#if FF_HAVE_VADRM + "va-drm\n" +#endif +#if FF_HAVE_VAX11 + "va-x11\n" #endif #if FF_HAVE_VDPAU "vdpau\n" diff --git a/src/common/impl/netif_gnu.c b/src/common/impl/netif_gnu.c index d2feed5be9..6593899a65 100644 --- a/src/common/impl/netif_gnu.c +++ b/src/common/impl/netif_gnu.c @@ -1,12 +1,10 @@ #include "common/netif.h" #include "common/io.h" +#include "common/strutil.h" #include #include -#define FF_STR_INDIR(x) #x -#define FF_STR(x) FF_STR_INDIR(x) - bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) { FILE* FF_AUTO_CLOSE_FILE netRoute = fopen("/proc/route", "r"); diff --git a/src/common/impl/networking_linux.c b/src/common/impl/networking_linux.c index e253451fee..7e40567927 100644 --- a/src/common/impl/networking_linux.c +++ b/src/common/impl/networking_linux.c @@ -56,7 +56,14 @@ static const char* tryNonThreadingFastPath(FFNetworkingState* state) { } #ifndef __APPLE__ - FF_DEBUG("Using sendto() + MSG_DONTWAIT to send %u bytes of data", state->command.length); + FF_DEBUG("Using sendto() " + #ifdef MSG_FASTOPEN + "+ MSG_FASTOPEN " + #endif + #ifdef MSG_NOSIGNAL + "+ MSG_NOSIGNAL " + #endif + "to send %u bytes of data", state->command.length); ssize_t sent = sendto(state->sockfd, state->command.chars, state->command.length, @@ -66,7 +73,7 @@ static const char* tryNonThreadingFastPath(FFNetworkingState* state) { #ifdef MSG_NOSIGNAL MSG_NOSIGNAL | #endif - MSG_DONTWAIT, + 0, state->addr->ai_addr, state->addr->ai_addrlen); #else diff --git a/src/common/impl/processing_linux.c b/src/common/impl/processing_linux.c index 2b87c3b793..828d4846d8 100644 --- a/src/common/impl/processing_linux.c +++ b/src/common/impl/processing_linux.c @@ -269,7 +269,7 @@ void ffProcessGetInfoLinux(pid_t pid, FFstrbuf* processName, FFstrbuf* exe, cons } } - if (exePath->length == 0) { + if (exePath->length == 0 && access(filePath, X_OK) == 0) { ffStrbufSetS(exePath, filePath); } } @@ -546,7 +546,7 @@ const char* ffProcessGetBasicInfoLinux(pid_t pid, FFstrbuf* name, pid_t* ppid, i return "sysctl(KERN_PROC_PID) failed"; } - ffStrbufSetS(name, proc.kp_proc.p_comm); // trancated to 16 chars + ffStrbufSetS(name, proc.kp_proc.p_comm); // truncated to 16 chars if (ppid) { *ppid = (pid_t) proc.kp_eproc.e_ppid; } diff --git a/src/common/io.h b/src/common/io.h index f7aec0b42f..e317120616 100644 --- a/src/common/io.h +++ b/src/common/io.h @@ -40,6 +40,7 @@ HANDLE openat(HANDLE dfd, const char* fileName, int oflag); HANDLE openatW(HANDLE dfd, const wchar_t* fileName, uint16_t fileNameLen, bool directory); #endif +FF_A_ALWAYS_INLINE static inline bool ffIsValidNativeFD(FFNativeFD fd) { #ifndef _WIN32 return fd >= 0; @@ -49,20 +50,17 @@ static inline bool ffIsValidNativeFD(FFNativeFD fd) { #endif } -FF_A_NONNULL(1) static inline bool wrapClose(FFNativeFD* pfd) { +FF_A_ALWAYS_INLINE FF_A_NONNULL(1) +static inline void wrapClose(FFNativeFD* pfd) { assert(pfd); - if (!ffIsValidNativeFD(*pfd)) { - return false; - } - + if (ffIsValidNativeFD(*pfd)) { #ifndef _WIN32 - close(*pfd); + close(*pfd); #else - NtClose(*pfd); + NtClose(*pfd); #endif - - return true; + } } #define FF_AUTO_CLOSE_FD FF_A_CLEANUP(wrapClose) @@ -250,34 +248,28 @@ static inline void ffUnsuppressIO(bool* suppressed) { void ffListFilesRecursively(const char* path, bool pretty); -FF_A_NONNULL(1) static inline bool wrapFclose(FILE** pfile) { +FF_A_NONNULL(1) FF_A_ALWAYS_INLINE static inline void wrapFclose(FILE** pfile) { assert(pfile); - if (!*pfile) { - return false; + if (*pfile) { + fclose(*pfile); } - fclose(*pfile); - return true; } #define FF_AUTO_CLOSE_FILE FF_A_CLEANUP(wrapFclose) -FF_A_NONNULL(1) +FF_A_NONNULL(1) FF_A_ALWAYS_INLINE #ifndef _WIN32 -static inline bool wrapClosedir(DIR** pdir) { +static inline void wrapClosedir(DIR** pdir) { assert(pdir); - if (!*pdir) { - return false; + if (*pdir) { + closedir(*pdir); } - closedir(*pdir); - return true; } #else -static inline bool wrapClosedir(HANDLE* pdir) { +static inline void wrapClosedir(HANDLE* pdir) { assert(pdir); - if (!*pdir) { - return false; + if (*pdir) { + FindClose(*pdir); } - FindClose(*pdir); - return true; } #endif #define FF_AUTO_CLOSE_DIR FF_A_CLEANUP(wrapClosedir) diff --git a/src/common/mallocHelper.h b/src/common/mallocHelper.h index 5b24df4713..a130118388 100644 --- a/src/common/mallocHelper.h +++ b/src/common/mallocHelper.h @@ -2,6 +2,7 @@ #include #include +#include "common/attributes.h" #if FF_HAVE_MALLOC_USABLE_SIZE || FF_HAVE_MSVC_MSIZE #if __has_include() @@ -13,6 +14,7 @@ #include #endif +FF_A_ALWAYS_INLINE FF_A_NONNULL(1) static inline void ffWrapFree(const void* pPtr) { assert(pPtr); if (*(void**) pPtr) { diff --git a/src/common/strutil.h b/src/common/strutil.h index 00a8a08398..6d8b639b11 100644 --- a/src/common/strutil.h +++ b/src/common/strutil.h @@ -5,6 +5,7 @@ #include #include +#include "common/attributes.h" #include "common/wcwidth.h" #ifdef _WIN32 @@ -13,6 +14,9 @@ __stdcall char* StrStrIA(const char* lpFirst, const char* lpSrch); #define strcasestr StrStrIA #endif +#define FF_STR_INDIR(x) #x +#define FF_STR(x) FF_STR_INDIR(x) + static inline bool ffStrSet(const char* str) { if (str == NULL) { return false; @@ -25,14 +29,17 @@ static inline bool ffStrSet(const char* str) { return *str != '\0'; } +FF_A_ALWAYS_INLINE static inline bool ffStrStartsWithIgnCase(const char* str, const char* compareTo) { return strncasecmp(str, compareTo, strlen(compareTo)) == 0; } +FF_A_ALWAYS_INLINE static inline bool ffStrEqualsIgnCase(const char* str, const char* compareTo) { return strcasecmp(str, compareTo) == 0; } +FF_A_ALWAYS_INLINE static inline bool ffStrStartsWith(const char* str, const char* compareTo) { return strncmp(str, compareTo, strlen(compareTo)) == 0; } @@ -55,26 +62,32 @@ static inline bool ffStrEndsWithIgnCase(const char* str, const char* compareTo) return strncasecmp(str + strLength - compareToLength, compareTo, compareToLength) == 0; } +FF_A_ALWAYS_INLINE static inline bool ffStrEquals(const char* str, const char* compareTo) { return strcmp(str, compareTo) == 0; } +FF_A_ALWAYS_INLINE static inline bool ffStrContains(const char* str, const char* compareTo) { return strstr(str, compareTo) != NULL; } +FF_A_ALWAYS_INLINE static inline bool ffStrContainsIgnCase(const char* str, const char* compareTo) { return strcasestr(str, compareTo) != NULL; } +FF_A_ALWAYS_INLINE static inline bool ffStrContainsC(const char* str, char compareTo) { return strchr(str, compareTo) != NULL; } +FF_A_ALWAYS_INLINE static inline bool ffCharIsEnglishAlphabet(char c) { return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); } +FF_A_ALWAYS_INLINE static inline bool ffCharIsDigit(char c) { return '0' <= c && c <= '9'; } @@ -86,6 +99,7 @@ uint8_t ffUtf8CharLenWidth(const char* str, uint32_t length, uint8_t* width); uint32_t ffUtf8StrWidth(const char* str, uint32_t length); +FF_A_ALWAYS_INLINE static inline bool ffCharIsHexDigit(char c) { return ffCharIsDigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F'); } diff --git a/src/detection/brightness/brightness_linux.c b/src/detection/brightness/brightness_linux.c index e7125f8fc1..c0012c4342 100644 --- a/src/detection/brightness/brightness_linux.c +++ b/src/detection/brightness/brightness_linux.c @@ -10,7 +10,7 @@ static const char* detectWithBacklight(FFlist* result) { // https://www.kernel.org/doc/Documentation/ABI/stable/sysfs-class-backlight const char* backlightDirPath = "/sys/class/backlight/"; - DIR* dirp = opendir(backlightDirPath); + FF_AUTO_CLOSE_DIR DIR* dirp = opendir(backlightDirPath); if (dirp == NULL) { return "Failed to open `/sys/class/backlight/`"; } @@ -72,8 +72,6 @@ static const char* detectWithBacklight(FFlist* result) { ffStrbufSubstrBefore(&backlightDir, backlightDirLength); } - closedir(dirp); - return NULL; } diff --git a/src/detection/codec/codec_linux.c b/src/detection/codec/codec_linux.c index c25614e83c..a6f817089b 100644 --- a/src/detection/codec/codec_linux.c +++ b/src/detection/codec/codec_linux.c @@ -1,35 +1,33 @@ #include "codec.h" -#if (FF_HAVE_DRM && FF_HAVE_VA) || FF_HAVE_VDPAU +#if FF_HAVE_VADRM || FF_HAVE_VAX11 + #define FF_HAVE_VA 1 +#endif + +#if FF_HAVE_VA || FF_HAVE_VDPAU #include "common/library.h" #include "common/mallocHelper.h" + #include "common/strutil.h" #include "common/io.h" - #if FF_HAVE_DRM && FF_HAVE_VA - #include "detection/gpu/gpu.h" + #if FF_HAVE_VA #include #include - #include - #include - #endif - - #include - - #if FF_HAVE_VDPAU - #include - #include -VdpStatus vdp_device_create_x11(void* display, int screen, VdpDevice* device, VdpGetProcAddress** get_proc_address); -void* XOpenDisplay(const char* display_name); -int XCloseDisplay(void* display); -int XDefaultScreen(void* display); - #endif - - #if FF_HAVE_DRM && FF_HAVE_VA - -static FFCodecType ffCodecProfileToType(VAProfile profile) { +typedef struct FFVAData { + FF_LIBRARY_SYMBOL(vaInitialize) + FF_LIBRARY_SYMBOL(vaTerminate) + FF_LIBRARY_SYMBOL(vaMaxNumProfiles) + FF_LIBRARY_SYMBOL(vaMaxNumEntrypoints) + FF_LIBRARY_SYMBOL(vaQueryConfigProfiles) + FF_LIBRARY_SYMBOL(vaQueryConfigEntrypoints) + FF_LIBRARY_SYMBOL(vaQueryVendorString) + FF_LIBRARY_SYMBOL(vaGetConfigAttributes) +} FFVAData; + +static FFCodecType vaProfileToType(VAProfile profile) { switch (profile) { case 11: // VAProfileH263Baseline return FF_CODEC_TYPE_H263; @@ -98,7 +96,7 @@ static FFCodecType ffCodecProfileToType(VAProfile profile) { } } -static FFCodecShowType ffCodecGetEntrypointType(VAEntrypoint entrypoint) { +static FFCodecShowType vaGetEntrypointType(VAEntrypoint entrypoint) { switch (entrypoint) { case VAEntrypointVLD: case VAEntrypointIDCT: @@ -113,21 +111,20 @@ static FFCodecShowType ffCodecGetEntrypointType(VAEntrypoint entrypoint) { } } -static bool ffCodecProfileHasOutput( +static bool vaProfileHasOutput( + FFVAData* vaData, VADisplay display, - __typeof__(vaQueryConfigEntrypoints)* ffvaQueryConfigEntrypoints, - __typeof__(vaGetConfigAttributes)* ffvaGetConfigAttributes, int maxEntrypoints, VAEntrypoint* entrypoints, VAProfile profile, FFCodecShowType entrypointType) { int numEntrypoints = maxEntrypoints; - if (ffvaQueryConfigEntrypoints(display, profile, entrypoints, &numEntrypoints) != VA_STATUS_SUCCESS) { + if (vaData->ffvaQueryConfigEntrypoints(display, profile, entrypoints, &numEntrypoints) != VA_STATUS_SUCCESS) { return false; } for (int i = 0; i < numEntrypoints; ++i) { - if (ffCodecGetEntrypointType(entrypoints[i]) != entrypointType) { + if (vaGetEntrypointType(entrypoints[i]) != entrypointType) { continue; } @@ -136,7 +133,7 @@ static bool ffCodecProfileHasOutput( .value = 0, }; - if (ffvaGetConfigAttributes(display, profile, entrypoints[i], &attrib, 1) == VA_STATUS_SUCCESS && + if (vaData->ffvaGetConfigAttributes(display, profile, entrypoints[i], &attrib, 1) == VA_STATUS_SUCCESS && attrib.value != VA_ATTRIB_NOT_SUPPORTED && attrib.value != 0) { return true; @@ -146,91 +143,101 @@ static bool ffCodecProfileHasOutput( return false; } -static void ffCodecFillGpuName(const drmDevice* dev, const char* path, FFstrbuf* name) { - ffStrbufInit(name); +static bool vaDetectDisplay(VADisplay display, FFVAData* vaData, FFCodecOptions* options, FFlist* result, const char* api) { + int major = 0, minor = 0; + if (vaData->ffvaInitialize(display, &major, &minor) != VA_STATUS_SUCCESS) { + vaData->ffvaTerminate(display); + return false; + } - switch (dev->bustype) { - case DRM_BUS_PCI: { - FFGPUResult gpu = { - .vendor = ffStrbufCreateStatic(ffGPUGetVendorString(dev->deviceinfo.pci->vendor_id)), - .name = ffStrbufCreate(), - }; + int maxProfiles = vaData->ffvaMaxNumProfiles(display); + int maxEntrypoints = vaData->ffvaMaxNumEntrypoints(display); + if (maxProfiles <= 0 || maxEntrypoints <= 0) { + vaData->ffvaTerminate(display); + return false; + } - ffGPUFillVendorAndName(0, dev->deviceinfo.pci->vendor_id, dev->deviceinfo.pci->device_id, &gpu); - ffStrbufSetF(name, "%s %s", gpu.vendor.chars, gpu.name.chars); + FF_AUTO_FREE VAProfile* profiles = (VAProfile*) malloc(sizeof(VAProfile) * (size_t) maxProfiles); + FF_AUTO_FREE VAEntrypoint* entrypoints = (VAEntrypoint*) malloc(sizeof(VAEntrypoint) * (size_t) maxEntrypoints); - ffStrbufDestroy(&gpu.vendor); - ffStrbufDestroy(&gpu.name); - break; - } - case DRM_BUS_PLATFORM: - ffStrbufSetS(name, dev->deviceinfo.platform->compatible[0]); - return; - case DRM_BUS_HOST1X: - ffStrbufSetS(name, dev->deviceinfo.host1x->compatible[0]); - return; - case DRM_BUS_USB: - ffStrbufSetF(name, "0x%04X 0x%04X", dev->deviceinfo.usb->vendor, dev->deviceinfo.usb->product); - return; - default: - ffStrbufSetStatic(name, "Unknown GPU"); - return; + int numProfiles = maxProfiles; + if (vaData->ffvaQueryConfigProfiles(display, profiles, &numProfiles) != VA_STATUS_SUCCESS) { + vaData->ffvaTerminate(display); + return false; } - if (!name->length && path && *path) { - const char* base = strrchr(path, '/'); - ffStrbufSetS(name, base ? base + 1 : path); + FFCodecType decoderTypes = FF_CODEC_TYPE_NONE; + FFCodecType encoderTypes = FF_CODEC_TYPE_NONE; + for (int j = 0; j < numProfiles; ++j) { + FFCodecType type = vaProfileToType(profiles[j]); + + bool hasDecoder = (options->showType & FF_CODEC_SHOW_TYPE_DECODER) && + !(decoderTypes & type) && + vaProfileHasOutput( + vaData, + display, + maxEntrypoints, + entrypoints, + profiles[j], + FF_CODEC_SHOW_TYPE_DECODER); + + bool hasEncoder = (options->showType & FF_CODEC_SHOW_TYPE_ENCODER) && + !(encoderTypes & type) && + vaProfileHasOutput( + vaData, + display, + maxEntrypoints, + entrypoints, + profiles[j], + FF_CODEC_SHOW_TYPE_ENCODER); + + if (!hasDecoder && !hasEncoder) { + continue; + } + + if (hasDecoder) { + decoderTypes |= type; + } + if (hasEncoder) { + encoderTypes |= type; + } } - if (!name->length) { - ffStrbufSetStatic(name, "Unknown GPU"); + if (decoderTypes != FF_CODEC_TYPE_NONE || encoderTypes != FF_CODEC_TYPE_NONE) { + FFCodecResult* item = FF_LIST_ADD(FFCodecResult, *result); + ffStrbufInitS(&item->gpu, vaData->ffvaQueryVendorString(display)); + item->decoders = decoderTypes; + item->encoders = encoderTypes; + item->platformApi = api; } -} -static const char* ffDetectCodecByVa(FFCodecOptions* options, FFlist* result) { - FF_LIBRARY_LOAD_MESSAGE(libdrm, "libdrm" FF_LIBRARY_EXTENSION, 2) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmGetDevices) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmFreeDevices) + vaData->ffvaTerminate(display); - FF_LIBRARY_LOAD_MESSAGE(libva, "libva" FF_LIBRARY_EXTENSION, 2) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libva, vaInitialize) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libva, vaTerminate) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libva, vaMaxNumProfiles) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libva, vaMaxNumEntrypoints) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libva, vaQueryConfigProfiles) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libva, vaQueryConfigEntrypoints) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libva, vaGetConfigAttributes) + return true; +} + + #if FF_HAVE_VADRM + #include +static const char* detectCodecByVaDrm(FFVAData* vaData, FFCodecOptions* options, FFlist* result) { FF_LIBRARY_LOAD_MESSAGE(libvaDrm, "libva-drm" FF_LIBRARY_EXTENSION, 2) FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libvaDrm, vaGetDisplayDRM) - drmDevicePtr devices[64]; - int numDevices = ffdrmGetDevices(devices, ARRAY_SIZE(devices)); - if (numDevices < 0) { - return "drmGetDevices() failed"; - } - if (numDevices == 0) { - return "No DRM devices found"; - } - const char* error = "No DRM device could initialize VA-API"; - for (int i = 0; i < numDevices; ++i) { - drmDevice* dev = devices[i]; + FF_AUTO_CLOSE_DIR DIR* dirp = opendir("/dev/dri/"); + if (dirp == NULL) { + return "opendir(/dev/dri/) failed"; + } + int drifd = dirfd(dirp); - const char* path = NULL; - if (dev->available_nodes & (1 << DRM_NODE_RENDER)) { - path = dev->nodes[DRM_NODE_RENDER]; - } else if (dev->available_nodes & (1 << DRM_NODE_PRIMARY)) { - path = dev->nodes[DRM_NODE_PRIMARY]; - } else { + struct dirent* entry; + while ((entry = readdir(dirp)) != NULL) { + if (entry->d_name[0] == '.' || !ffStrStartsWith(entry->d_name, "renderD")) { continue; } - FF_AUTO_CLOSE_FD int fd = open(path, O_RDWR | O_CLOEXEC); - if (fd < 0) { - fd = open(path, O_RDONLY | O_CLOEXEC); - } + FF_AUTO_CLOSE_FD int fd = openat(drifd, entry->d_name, O_RDONLY | O_CLOEXEC); if (fd < 0) { continue; } @@ -240,84 +247,74 @@ static const char* ffDetectCodecByVa(FFCodecOptions* options, FFlist* result) { continue; } - int major = 0, minor = 0; - if (ffvaInitialize(display, &major, &minor) != VA_STATUS_SUCCESS) { - continue; + if (vaDetectDisplay(display, vaData, options, result, "VA-API (DRM)")) { + error = NULL; } - error = NULL; + } - int maxProfiles = ffvaMaxNumProfiles(display); - int maxEntrypoints = ffvaMaxNumEntrypoints(display); - if (maxProfiles <= 0 || maxEntrypoints <= 0) { - ffvaTerminate(display); - continue; - } + return error; +} + #endif + #if FF_HAVE_VAX11 + #include - FF_AUTO_FREE VAProfile* profiles = (VAProfile*) malloc(sizeof(VAProfile) * (size_t) maxProfiles); - FF_AUTO_FREE VAEntrypoint* entrypoints = (VAEntrypoint*) malloc(sizeof(VAEntrypoint) * (size_t) maxEntrypoints); +static const char* detectCodecByVaX11(FFVAData* vaData, FFCodecOptions* options, FFlist* result) { + FF_LIBRARY_LOAD_MESSAGE(libX11, "libX11" FF_LIBRARY_EXTENSION, 6) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libX11, XOpenDisplay) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libX11, XCloseDisplay) - int numProfiles = maxProfiles; - if (ffvaQueryConfigProfiles(display, profiles, &numProfiles) != VA_STATUS_SUCCESS) { - ffvaTerminate(display); - continue; - } + Display* x11Display = ffXOpenDisplay(NULL); + if (!x11Display) { + return "XOpenDisplay() failed"; + } - FFCodecType decoderTypes = FF_CODEC_TYPE_NONE; - FFCodecType encoderTypes = FF_CODEC_TYPE_NONE; - for (int j = 0; j < numProfiles; ++j) { - FFCodecType type = ffCodecProfileToType(profiles[j]); - - bool hasDecoder = (options->showType & FF_CODEC_SHOW_TYPE_DECODER) && - !(decoderTypes & type) && - ffCodecProfileHasOutput( - display, - ffvaQueryConfigEntrypoints, - ffvaGetConfigAttributes, - maxEntrypoints, - entrypoints, - profiles[j], - FF_CODEC_SHOW_TYPE_DECODER); - - bool hasEncoder = (options->showType & FF_CODEC_SHOW_TYPE_ENCODER) && - !(encoderTypes & type) && - ffCodecProfileHasOutput( - display, - ffvaQueryConfigEntrypoints, - ffvaGetConfigAttributes, - maxEntrypoints, - entrypoints, - profiles[j], - FF_CODEC_SHOW_TYPE_ENCODER); - - if (!hasDecoder && !hasEncoder) { - continue; - } - - if (hasDecoder) { - decoderTypes |= type; - } - if (hasEncoder) { - encoderTypes |= type; - } - } + FF_LIBRARY_LOAD_MESSAGE(libvaX11, "libva-x11" FF_LIBRARY_EXTENSION, 2) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libvaX11, vaGetDisplay) - if (decoderTypes != FF_CODEC_TYPE_NONE || encoderTypes != FF_CODEC_TYPE_NONE) { - FFCodecResult* item = FF_LIST_ADD(FFCodecResult, *result); - ffCodecFillGpuName(dev, path, &item->gpu); - item->decoders = decoderTypes; - item->encoders = encoderTypes; - item->platformApi = "VA-API"; - } + VADisplay display = ffvaGetDisplay(x11Display); + if (!display) { + return "vaGetDisplay() failed"; + } - ffvaTerminate(display); + if (!vaDetectDisplay(display, vaData, options, result, "VA-API (X11)")) { + return "VA-API could not detect any supported codec via X11"; } - ffdrmFreeDevices(devices, numDevices); - return error; + return NULL; +} + #endif + +static const char* detectCodecByVa(FFCodecOptions* options, FFlist* result) { + FFVAData vaData = {}; + + FF_LIBRARY_LOAD_MESSAGE(libva, "libva" FF_LIBRARY_EXTENSION, 2) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libva, vaData, vaInitialize) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libva, vaData, vaTerminate) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libva, vaData, vaMaxNumProfiles) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libva, vaData, vaMaxNumEntrypoints) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libva, vaData, vaQueryConfigProfiles) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libva, vaData, vaQueryConfigEntrypoints) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libva, vaData, vaQueryVendorString) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libva, vaData, vaGetConfigAttributes) + + #if FF_HAVE_VADRM + if (detectCodecByVaDrm(&vaData, options, result) == NULL) { + return NULL; + } + #endif + + #if FF_HAVE_VAX11 + if (detectCodecByVaX11(&vaData, options, result) == NULL) { + return NULL; + } + #endif + + return "VA-API could not detect any supported codec via DRM or X11"; } #endif #if FF_HAVE_VDPAU + #include static const struct FFCodecVdpauCodec { VdpDecoderProfile profile; @@ -326,6 +323,13 @@ static const struct FFCodecVdpauCodec { { 0, FF_CODEC_TYPE_MPEG1 }, // VDP_DECODER_PROFILE_MPEG1 { 1, FF_CODEC_TYPE_MPEG2 }, // VDP_DECODER_PROFILE_MPEG2_SIMPLE { 2, FF_CODEC_TYPE_MPEG2 }, // VDP_DECODER_PROFILE_MPEG2_MAIN + + { 6, FF_CODEC_TYPE_H264 }, // VDP_DECODER_PROFILE_H264_BASELINE + { 7, FF_CODEC_TYPE_H264 }, // VDP_DECODER_PROFILE_H264_MAIN + { 8, FF_CODEC_TYPE_H264 }, // VDP_DECODER_PROFILE_H264_HIGH + { 9, FF_CODEC_TYPE_VC1 }, // VDP_DECODER_PROFILE_VC1_SIMPLE + { 10, FF_CODEC_TYPE_VC1 }, // VDP_DECODER_PROFILE_VC1_MAIN + { 11, FF_CODEC_TYPE_VC1 }, // VDP_DECODER_PROFILE_VC1_ADVANCED { 12, FF_CODEC_TYPE_DIVX_XVID }, // VDP_DECODER_PROFILE_MPEG4_PART2_SP { 13, FF_CODEC_TYPE_DIVX_XVID }, // VDP_DECODER_PROFILE_MPEG4_PART2_ASP { 14, FF_CODEC_TYPE_DIVX_XVID }, // VDP_DECODER_PROFILE_DIVX4_QMOBILE @@ -336,17 +340,16 @@ static const struct FFCodecVdpauCodec { { 19, FF_CODEC_TYPE_DIVX_XVID }, // VDP_DECODER_PROFILE_DIVX5_MOBILE { 20, FF_CODEC_TYPE_DIVX_XVID }, // VDP_DECODER_PROFILE_DIVX5_HOME_THEATER { 21, FF_CODEC_TYPE_DIVX_XVID }, // VDP_DECODER_PROFILE_DIVX5_HD_1080P - { 6, FF_CODEC_TYPE_H264 }, // VDP_DECODER_PROFILE_H264_BASELINE - { 7, FF_CODEC_TYPE_H264 }, // VDP_DECODER_PROFILE_H264_MAIN - { 8, FF_CODEC_TYPE_H264 }, // VDP_DECODER_PROFILE_H264_HIGH { 22, FF_CODEC_TYPE_H264 }, // VDP_DECODER_PROFILE_H264_CONSTRAINED_BASELINE { 23, FF_CODEC_TYPE_H264 }, // VDP_DECODER_PROFILE_H264_EXTENDED { 24, FF_CODEC_TYPE_H264 }, // VDP_DECODER_PROFILE_H264_PROGRESSIVE_HIGH { 25, FF_CODEC_TYPE_H264 }, // VDP_DECODER_PROFILE_H264_CONSTRAINED_HIGH { 26, FF_CODEC_TYPE_H264 }, // VDP_DECODER_PROFILE_H264_HIGH_444_PREDICTIVE - { 9, FF_CODEC_TYPE_VC1 }, // VDP_DECODER_PROFILE_VC1_SIMPLE - { 10, FF_CODEC_TYPE_VC1 }, // VDP_DECODER_PROFILE_VC1_MAIN - { 11, FF_CODEC_TYPE_VC1 }, // VDP_DECODER_PROFILE_VC1_ADVANCED + { 27, FF_CODEC_TYPE_VP9 }, // VDP_DECODER_PROFILE_VP9_PROFILE_0 + { 28, FF_CODEC_TYPE_VP9 }, // VDP_DECODER_PROFILE_VP9_PROFILE_1 + { 29, FF_CODEC_TYPE_VP9 }, // VDP_DECODER_PROFILE_VP9_PROFILE_2 + { 30, FF_CODEC_TYPE_VP9 }, // VDP_DECODER_PROFILE_VP9_PROFILE_3 + { 100, FF_CODEC_TYPE_HEVC }, // VDP_DECODER_PROFILE_HEVC_MAIN { 101, FF_CODEC_TYPE_HEVC }, // VDP_DECODER_PROFILE_HEVC_MAIN_10 { 102, FF_CODEC_TYPE_HEVC }, // VDP_DECODER_PROFILE_HEVC_MAIN_STILL @@ -354,17 +357,13 @@ static const struct FFCodecVdpauCodec { { 104, FF_CODEC_TYPE_HEVC }, // VDP_DECODER_PROFILE_HEVC_MAIN_444 { 105, FF_CODEC_TYPE_HEVC }, // VDP_DECODER_PROFILE_HEVC_MAIN_444_10 { 106, FF_CODEC_TYPE_HEVC }, // VDP_DECODER_PROFILE_HEVC_MAIN_444_12 - { 27, FF_CODEC_TYPE_VP9 }, // VDP_DECODER_PROFILE_VP9_PROFILE_0 - { 28, FF_CODEC_TYPE_VP9 }, // VDP_DECODER_PROFILE_VP9_PROFILE_1 - { 29, FF_CODEC_TYPE_VP9 }, // VDP_DECODER_PROFILE_VP9_PROFILE_2 - { 30, FF_CODEC_TYPE_VP9 }, // VDP_DECODER_PROFILE_VP9_PROFILE_3 { 107, FF_CODEC_TYPE_AV1 }, // VDP_DECODER_PROFILE_AV1_MAIN { 108, FF_CODEC_TYPE_AV1 }, // VDP_DECODER_PROFILE_AV1_HIGH { 109, FF_CODEC_TYPE_AV1 }, // VDP_DECODER_PROFILE_AV1_PROFESSIONAL }; -static const char* ffDetectCodecByVdpau(FFCodecOptions* options, FFlist* result) { - if (options->showType == FF_CODEC_SHOW_TYPE_DECODER) { +static const char* detectCodecByVdpau(FFCodecOptions* options, FFlist* result) { + if (!(options->showType & FF_CODEC_SHOW_TYPE_DECODER)) { return "VDPAU only supports decoding"; } @@ -373,14 +372,14 @@ static const char* ffDetectCodecByVdpau(FFCodecOptions* options, FFlist* result) FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libX11, XCloseDisplay) FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libX11, XDefaultScreen) - FF_LIBRARY_LOAD_MESSAGE(libvdpau, "libvdpau" FF_LIBRARY_EXTENSION, 1) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libvdpau, vdp_device_create_x11) - - void* x11Display = ffXOpenDisplay(NULL); + Display* x11Display = ffXOpenDisplay(NULL); if (!x11Display) { return "XOpenDisplay() failed"; } + FF_LIBRARY_LOAD_MESSAGE(libvdpau, "libvdpau" FF_LIBRARY_EXTENSION, 1) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libvdpau, vdp_device_create_x11) + VdpDevice device = VDP_INVALID_HANDLE; VdpGetProcAddress* ffvdp_get_proc_address = NULL; if (ffvdp_device_create_x11(x11Display, ffXDefaultScreen(x11Display), &device, &ffvdp_get_proc_address) != VDP_STATUS_OK || @@ -446,13 +445,13 @@ static const char* ffDetectCodecByVdpau(FFCodecOptions* options, FFlist* result) const char* ffDetectCodecNative(FFCodecOptions* options, FFlist* result /* list of FFCodecResult */) { FF_SUPPRESS_IO(); - #if FF_HAVE_DRM && FF_HAVE_VA - if (ffDetectCodecByVa(options, result) == NULL) { + #if FF_HAVE_VA + if (detectCodecByVa(options, result) == NULL) { return NULL; } #endif #if FF_HAVE_VDPAU - if (ffDetectCodecByVdpau(options, result) == NULL) { + if (detectCodecByVdpau(options, result) == NULL) { return NULL; } #endif @@ -464,7 +463,7 @@ const char* ffDetectCodecNative(FFCodecOptions* options, FFlist* result /* list const char* ffDetectCodecNative(FFCodecOptions* options, FFlist* result /* list of FFCodecResult */) { FF_UNUSED(options, result); - return "Fastfetch was built without DRM / VA-API / VDPAU headers"; + return "Fastfetch was built without VA-API / VDPAU headers"; } #endif diff --git a/src/detection/codec/codec_windows.cpp b/src/detection/codec/codec_windows.cpp index df01a63789..9e2183959a 100644 --- a/src/detection/codec/codec_windows.cpp +++ b/src/detection/codec/codec_windows.cpp @@ -408,13 +408,13 @@ const char* detectD3d11va(FFCodecOptions* options, FFlist* result /*list of FFCo FF_LIBRARY_LOAD_SYMBOL_MESSAGE(d3d11, D3D11CreateDevice) FF_LIBRARY_LOAD_MESSAGE(mfplat, "mfplat" FF_LIBRARY_EXTENSION, 1) FF_LIBRARY_LOAD_SYMBOL_MESSAGE(mfplat, MFCreateAttributes) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(mfplat, MFTEnum2) + FF_LIBRARY_LOAD_SYMBOL_LAZY(mfplat, MFTEnum2) // Not available on Windows 8.1 ffEnumHardwareAdapters(factory, [&](IDXGIAdapter1* adapter, const DXGI_ADAPTER_DESC1& desc) { FFCodecType decoders = (options->showType & FF_CODEC_SHOW_TYPE_DECODER) ? ffDetectD3d11vaDecoders(adapter, ffD3D11CreateDevice) : FF_CODEC_TYPE_NONE; - FFCodecType encoders = (options->showType & FF_CODEC_SHOW_TYPE_ENCODER) + FFCodecType encoders = ffMFTEnum2 && (options->showType & FF_CODEC_SHOW_TYPE_ENCODER) ? ffDetectD3d11MftEncoders(desc.AdapterLuid, ffMFCreateAttributes, ffMFTEnum2) : FF_CODEC_TYPE_NONE; @@ -426,7 +426,7 @@ const char* detectD3d11va(FFCodecOptions* options, FFlist* result /*list of FFCo ffStrbufInitWS(&gpuResult->gpu, desc.Description); gpuResult->decoders = decoders; gpuResult->encoders = encoders; - gpuResult->platformApi = "D3D11VA+MFT"; + gpuResult->platformApi = ffMFTEnum2 ? "D3D11VA+MFT" : "D3D11VA"; }); return nullptr; diff --git a/src/detection/cpu/cpu.c b/src/detection/cpu/cpu.c index aadcdc452d..155c0328c8 100644 --- a/src/detection/cpu/cpu.c +++ b/src/detection/cpu/cpu.c @@ -22,6 +22,11 @@ const char* ffDetectCPU(const FFCPUOptions* options, FFCPUResult* cpu) { ffStrbufSubstrBeforeFirstC(&cpu->name, '@'); // Cut the speed output in the name as we append our own ffStrbufTrimRight(&cpu->name, ' '); // If we removed the @ in previous step there was most likely a space before it ffStrbufRemoveDupWhitespaces(&cpu->name); + +#if __i386__ || __x86_64__ + ffCPUDetectX86Specific(cpu); +#endif + return NULL; } diff --git a/src/detection/cpu/cpu.h b/src/detection/cpu/cpu.h index 0f7eeceb53..4e47ca10a6 100644 --- a/src/detection/cpu/cpu.h +++ b/src/detection/cpu/cpu.h @@ -27,9 +27,20 @@ typedef struct FFCPUResult { FFCPUCore coreTypes[16]; // number of P cores, E cores, etc. double temperature; + + #if __i386__ || __x86_64__ + const char* codeName; + const char* technology; + #endif } FFCPUResult; const char* ffDetectCPU(const FFCPUOptions* options, FFCPUResult* cpu); const char* ffCPUAppleCodeToName(uint32_t code); const char* ffCPUQualcommCodeToName(uint32_t code); void ffCPUDetectByCpuid(FFCPUResult* cpu); + +#if __i386__ || __x86_64__ + +bool ffCPUDetectX86Specific(FFCPUResult* cpu); + +#endif diff --git a/src/detection/cpu/cpu_linux.c b/src/detection/cpu/cpu_linux.c index b228d5230b..6a617727ec 100644 --- a/src/detection/cpu/cpu_linux.c +++ b/src/detection/cpu/cpu_linux.c @@ -619,19 +619,14 @@ static const char* parseCpuInfo( return NULL; } -static uint32_t getFrequency(FFstrbuf* basePath, const char* cpuinfoFileName, const char* scalingFileName, FFstrbuf* buffer) { - uint32_t baseLen = basePath->length; - ffStrbufAppendS(basePath, cpuinfoFileName); - bool ok = ffReadFileBuffer(basePath->chars, buffer); - ffStrbufSubstrBefore(basePath, baseLen); +static uint32_t getFrequency(int policyFd, const char* cpuinfoFileName, const char* scalingFileName, FFstrbuf* buffer) { + bool ok = ffReadFileBufferRelative(policyFd, cpuinfoFileName, buffer); if (ok) { return (uint32_t) (ffStrbufToUInt(buffer, 0) / 1000); } if (scalingFileName) { - ffStrbufAppendS(basePath, scalingFileName); - ok = ffReadFileBuffer(basePath->chars, buffer); - ffStrbufSubstrBefore(basePath, baseLen); + ok = ffReadFileBufferRelative(policyFd, scalingFileName, buffer); if (ok) { return (uint32_t) (ffStrbufToUInt(buffer, 0) / 1000); } @@ -640,55 +635,38 @@ static uint32_t getFrequency(FFstrbuf* basePath, const char* cpuinfoFileName, co return 0; } -static uint8_t getNumCores(FFstrbuf* basePath, FFstrbuf* buffer) { - uint32_t baseLen = basePath->length; - ffStrbufAppendS(basePath, "/affected_cpus"); - bool ok = ffReadFileBuffer(basePath->chars, buffer); - ffStrbufSubstrBefore(basePath, baseLen); - if (ok) { - return (uint8_t) (ffStrbufCountC(buffer, ' ') + 1); - } - - ffStrbufAppendS(basePath, "/related_cpus"); - ok = ffReadFileBuffer(basePath->chars, buffer); - ffStrbufSubstrBefore(basePath, baseLen); - if (ok) { - return (uint8_t) (ffStrbufCountC(buffer, ' ') + 1); - } - - return 0; -} - static bool detectFrequency(FFCPUResult* cpu, const FFCPUOptions* options) { - FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateS("/sys/devices/system/cpu/cpufreq/"); - FF_AUTO_CLOSE_DIR DIR* dir = opendir(path.chars); + const char* basePath = "/sys/devices/system/cpu/cpufreq/"; + FF_AUTO_CLOSE_DIR DIR* dir = opendir(basePath); if (!dir) { return false; } + int freqFd = dirfd(dir); FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate(); - uint32_t baseLen = path.length; struct dirent* entry; while ((entry = readdir(dir)) != NULL) { if (ffStrStartsWith(entry->d_name, "policy") && ffCharIsDigit(entry->d_name[strlen("policy")])) { - ffStrbufAppendS(&path, entry->d_name); + FF_AUTO_CLOSE_FD int policyFd = openat(freqFd, entry->d_name, O_RDONLY | O_DIRECTORY | O_CLOEXEC | O_PATH); + if (policyFd < 0) { + continue; + } - uint32_t fmax = getFrequency(&path, "/cpuinfo_max_freq", "/scaling_max_freq", &buffer); + uint32_t fmax = getFrequency(policyFd, "cpuinfo_max_freq", "scaling_max_freq", &buffer); if (fmax == 0) { continue; } if (cpu->frequencyMax >= fmax) { if (!options->showPeCoreCount) { - ffStrbufSubstrBefore(&path, baseLen); continue; } } else { cpu->frequencyMax = fmax; } - uint32_t fbase = getFrequency(&path, "/base_frequency", NULL, &buffer); + uint32_t fbase = getFrequency(policyFd, "base_frequency", NULL, &buffer); if (fbase > 0) { cpu->frequencyBase = cpu->frequencyBase > fbase ? cpu->frequencyBase : fbase; } @@ -702,9 +680,10 @@ static bool detectFrequency(FFCPUResult* cpu, const FFCPUOptions* options) { if (cpu->coreTypes[ifreq].freq == 0) { cpu->coreTypes[ifreq].freq = freq; } - cpu->coreTypes[ifreq].count += getNumCores(&path, &buffer); + if (ffReadFileBufferRelative(policyFd, "affected_cpus", &buffer)) { + cpu->coreTypes[ifreq].count += ffStrbufCountC(&buffer, ' ') + 1; + } } - ffStrbufSubstrBefore(&path, baseLen); } } return true; @@ -773,6 +752,7 @@ static const char* detectPhysicalCores(FFCPUResult* cpu) { FF_AUTO_CLOSE_DIR DIR* dir = fdopendir(dfd); if (!dir) { + close(dfd); return "fdopendir(dfd) failed"; } @@ -785,7 +765,7 @@ static const char* detectPhysicalCores(FFCPUResult* cpu) { continue; } - FF_AUTO_CLOSE_FD int cpuxfd = openat(dirfd(dir), entry->d_name, O_RDONLY | O_DIRECTORY); + FF_AUTO_CLOSE_FD int cpuxfd = openat(dirfd(dir), entry->d_name, O_RDONLY | O_DIRECTORY | O_CLOEXEC); if (cpuxfd < 0) { continue; } @@ -798,45 +778,42 @@ static const char* detectPhysicalCores(FFCPUResult* cpu) { ssize_t len = ffReadFileDataRelative(cpuxfd, "topology/physical_package_id", sizeof(buf) - 1, buf); if (len > 0) { buf[len] = '\0'; - unsigned long long id = strtoul(buf, NULL, 10); - if (__builtin_expect(id > 64, false)) { // Do 129-socket boards exist? - pkgHigh |= 1ULL << (id - 64); - } else { - pkgLow |= 1ULL << id; + unsigned long long id = strtoull(buf, NULL, 10); + if (__builtin_expect(id < 128, true)) { + // Do 129-socket boards exist? + if (__builtin_expect(id >= 64, false)) { + pkgHigh |= 1ULL << (id - 64); + } else { + pkgLow |= 1ULL << id; + } } } // Check if the directory contains a file named "topology/core_cpus_list" - // that lists the physical cores in the package. + // that lists the logical cores in the same physical core. len = ffReadFileDataRelative(cpuxfd, "topology/core_cpus_list", sizeof(buf) - 1, buf); if (len > 0) { - buf[len] = '\0'; // low-high or low - - for (const char* p = buf; *p;) { - char* pend; - uint32_t coreId = (uint32_t) strtoul(p, &pend, 10); - if (pend == p) { - break; - } + buf[len] = '\0'; // low[-high, low-high, ...] - bool found = false; - FF_LIST_FOR_EACH (uint32_t, id, cpuList) { - if (*id == coreId) { - // This core is already counted - found = true; - break; - } - } - if (!found) { - *FF_LIST_ADD(uint32_t, cpuList) = coreId; - } + char* pend; + // We assume that the different physical cores exposes different logical core ids, + // so that the first `low` is always different between different physical cores. + uint32_t coreId = (uint32_t) strtoul(buf, &pend, 10); + if (pend == buf) { + break; + } - p = strchr(pend, ','); - if (!p) { + bool found = false; + FF_LIST_FOR_EACH (uint32_t, id, cpuList) { + if (*id == coreId) { + // This core is already counted + found = true; break; } - ++p; + } + if (!found) { + *FF_LIST_ADD(uint32_t, cpuList) = coreId; } } } diff --git a/src/detection/cpu/cpu_windows.c b/src/detection/cpu/cpu_windows.c index 86edce912e..078ba0b837 100644 --- a/src/detection/cpu/cpu_windows.c +++ b/src/detection/cpu/cpu_windows.c @@ -216,7 +216,21 @@ static const char* detectMaxSpeedBySmbios(FFCPUResult* cpu) { return NULL; } -static const char* detectNCores(FFCPUResult* cpu) { +static uint32_t getNumLogicalCores(const SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* ptr) { + uint32_t num = 0; + for (uint32_t i = 0; i < ptr->Processor.GroupCount; ++i) { + num += (uint32_t) +#if _WIN64 + __builtin_popcountll +#else + __builtin_popcountl +#endif + (ptr->Processor.GroupMask[i].Mask); + } + return num; +} + +static const char* detectNCores(const FFCPUOptions* options, FFCPUResult* cpu) { LOGICAL_PROCESSOR_RELATIONSHIP lpr = RelationAll; ULONG length = 0; NtQuerySystemInformationEx(SystemLogicalProcessorAndGroupInformation, &lpr, sizeof(lpr), NULL, 0, &length); @@ -242,6 +256,19 @@ static const char* detectNCores(FFCPUResult* cpu) { } } else if (ptr->Relationship == RelationProcessorCore) { ++cpu->coresPhysical; + + if (options->showPeCoreCount) { + for (uint32_t i = 0; i < ARRAY_SIZE(cpu->coreTypes); ++i) { + if (ptr->Processor.EfficiencyClass + 1 == cpu->coreTypes[i].freq) { + cpu->coreTypes[i].count += getNumLogicalCores(ptr); + break; + } else if (cpu->coreTypes[i].freq == 0) { + cpu->coreTypes[i].freq = ptr->Processor.EfficiencyClass + 1; + cpu->coreTypes[i].count += getNumLogicalCores(ptr); + break; + } + } + } } else if (ptr->Relationship == RelationProcessorPackage) { ++cpu->packages; } else if (ptr->Relationship == RelationNumaNode) { @@ -258,7 +285,7 @@ static const char* detectByRegistry(FFCPUResult* cpu) { return "ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L\"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0\", &hKey, NULL) failed"; } - if (ffRegReadValues(hKey, 3, (FFRegValueArg[]) { + if (ffRegReadValues(hKey, 3, (FFRegValueArg[]){ FF_ARG(cpu->name, L"ProcessorNameString"), FF_ARG(cpu->vendor, L"VendorIdentifier"), FF_ARG(cpu->frequencyBase, L"~MHz"), @@ -272,31 +299,8 @@ static const char* detectByRegistry(FFCPUResult* cpu) { return NULL; } -static const char* detectCoreTypes(FFCPUResult* cpu) { - FF_AUTO_FREE PROCESSOR_POWER_INFORMATION* pinfo = calloc(cpu->coresLogical, sizeof(PROCESSOR_POWER_INFORMATION)); - if (!NT_SUCCESS(NtPowerInformation(ProcessorInformation, NULL, 0, pinfo, (ULONG) sizeof(PROCESSOR_POWER_INFORMATION) * cpu->coresLogical))) { - return "NtPowerInformation(ProcessorInformation, NULL, 0, pinfo, size) failed"; - } - - for (uint32_t icore = 0; icore < cpu->coresLogical && pinfo[icore].MhzLimit; ++icore) { - uint32_t ifreq = 0; - while (cpu->coreTypes[ifreq].freq != pinfo[icore].MhzLimit && cpu->coreTypes[ifreq].freq > 0) { - ++ifreq; - } - if (cpu->coreTypes[ifreq].freq == 0) { - cpu->coreTypes[ifreq].freq = pinfo[icore].MhzLimit; - } - ++cpu->coreTypes[ifreq].count; - } - - if (cpu->frequencyBase == 0) { - cpu->frequencyBase = pinfo->MaxMhz; - } - return NULL; -} - const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) { - detectNCores(cpu); + detectNCores(options, cpu); const char* error = detectByRegistry(cpu); if (error) { @@ -304,9 +308,6 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) { } ffCPUDetectByCpuid(cpu); - if (options->showPeCoreCount) { - detectCoreTypes(cpu); - } if (cpu->frequencyMax == 0) { detectMaxSpeedBySmbios(cpu); diff --git a/src/detection/cpu/cpu_x86.c b/src/detection/cpu/cpu_x86.c new file mode 100644 index 0000000000..9deb103745 --- /dev/null +++ b/src/detection/cpu/cpu_x86.c @@ -0,0 +1,1388 @@ +#include "cpu.h" + +#if __x86_64__ || __i386__ + #include + #include "common/strutil.h" + + #define UNKN_STR "Unknown" + +typedef struct match_entry_t { + int32_t family, model, stepping, ext_family, ext_model; // -1 means wildcard + int32_t ncores, l2cache, l3cache; + struct { + const char* pattern; + int32_t score; + } brand; + const char* name; + const char* technology; +} FFCPUX86MatchEntry; + +/////////////////////////////////////////////////////////////////////////////////////////////// + +// clang-format off + +// From libcpuid: https://github.com/anrieff/libcpuid +// LICENSE: BSD-2-Clause + +/****************************************** Intel ****************************************** */ + +// https://github.com/anrieff/libcpuid/blob/2e4456ae0165db3155da2e8fba92afd5c090ca1b/libcpuid/recog_intel.c +/* + * Copyright 2008 Veselin Georgiev, + * anrieffNOSPAM @ mgail_DOT.com (convert to gmail) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Useful links: + * - List of Intel CPU microarchitectures: https://en.wikipedia.org/wiki/List_of_Intel_CPU_microarchitectures + * - List of Intel processors: https://en.wikipedia.org/wiki/List_of_Intel_processors + * - List of Intel Pentium processors: https://en.wikipedia.org/wiki/List_of_Intel_Pentium_processors + * - List of Intel Celeron processors: https://en.wikipedia.org/wiki/List_of_Intel_Celeron_processors + * - List of Intel Core processors: https://en.wikipedia.org/wiki/List_of_Intel_Core_processors + * - List of Intel Xeon processors: https://en.wikipedia.org/wiki/List_of_Intel_Xeon_processors +*/ +const struct match_entry_t cpudb_intel[] = { +// F M S EF EM #cores L2$ L3$ Pattern Codename Technology + { -1, -1, -1, -1, -1, 1, -1, -1, { "", 0 }, "Unknown Intel CPU", UNKN_STR }, + + /* i486 */ + { 4, -1, -1, -1, -1, 1, -1, -1, { "", 0 }, "Unknown i486", UNKN_STR }, + { 4, 0, -1, -1, -1, 1, -1, -1, { "", 0 }, "i486 DX-25/33", "1 µm" }, + { 4, 1, -1, -1, -1, 1, -1, -1, { "", 0 }, "i486 DX-50", "0.8 µm" }, + { 4, 2, -1, -1, -1, 1, -1, -1, { "", 0 }, "i486 SX", UNKN_STR }, + { 4, 3, -1, -1, -1, 1, -1, -1, { "", 0 }, "i486 DX2", UNKN_STR }, + { 4, 4, -1, -1, -1, 1, -1, -1, { "", 0 }, "i486 SL", "0.8 µm" }, + { 4, 5, -1, -1, -1, 1, -1, -1, { "", 0 }, "i486 SX2", UNKN_STR }, + { 4, 7, -1, -1, -1, 1, -1, -1, { "", 0 }, "i486 DX2 WriteBack", UNKN_STR }, + { 4, 8, -1, -1, -1, 1, -1, -1, { "", 0 }, "i486 DX4", "0.6 µm" }, + { 4, 9, -1, -1, -1, 1, -1, -1, { "", 0 }, "i486 DX4 WriteBack", "0.6 µm" }, + + /* P6 CPUs */ + { 5, 0, -1, -1, -1, 1, -1, -1, { "Pentium(R)", 2 }, "Pentium A-Step", UNKN_STR }, + { 5, 1, -1, -1, -1, 1, -1, -1, { "Pentium(R)", 2 }, "Pentium 1", "0.8 µm" }, + { 5, 2, -1, -1, -1, 1, -1, -1, { "Pentium(R)", 2 }, "Pentium 1", "0.35 µm" }, + { 5, 3, -1, -1, -1, 1, -1, -1, { "Pentium(R)", 2 }, "Pentium OverDrive", UNKN_STR }, + { 5, 4, -1, -1, -1, 1, -1, -1, { "Pentium(R)", 2 }, "Pentium 1", "0.35 µm" }, + { 5, 7, -1, -1, -1, 1, -1, -1, { "Pentium(R)", 2 }, "Pentium 1", "0.35 µm" }, + { 5, 8, -1, -1, -1, 1, -1, -1, { "Pentium(R)", 2 }, "Pentium MMX", "0.25 µm" }, + + /* P6 CPUs */ + { 6, 0, -1, -1, -1, 1, -1, -1, { "Pentium(R)", 2 }, "Pentium Pro", UNKN_STR }, + { 6, 1, -1, -1, -1, 1, -1, -1, { "Pentium(R)", 2 }, "Pentium Pro", UNKN_STR }, + { 6, 3, -1, -1, -1, 1, -1, -1, { "Pentium(R)", 2 }, "Pentium II (Klamath)", "0.18 µm" }, + { 6, 5, -1, -1, -1, 1, -1, -1, { "Pentium(R)", 2 }, "Pentium II (Deschutes)", "0.18 µm" }, + { 6, 5, -1, -1, -1, 1, -1, -1, { "Pentium(R) M", 4 }, "Mobile Pentium II (Tonga)", "0.18 µm" }, + { 6, 6, -1, -1, -1, 1, -1, -1, { "Pentium(R)", 2 }, "Pentium II (Dixon)", "0.25 µm" }, + { 6, 3, -1, -1, -1, 1, -1, -1, { "Xeon(TM)", 2 }, "P-II Xeon (Klamath)", "0.35 µm" }, + { 6, 5, -1, -1, -1, 1, -1, -1, { "Xeon(TM)", 2 }, "P-II Xeon (Drake)", "0.25 µm" }, + { 6, 6, -1, -1, -1, 1, -1, -1, { "Xeon(TM)", 2 }, "P-II Xeon (Dixon)", "0.25 µm" }, + { 6, 5, -1, -1, -1, 1, -1, -1, { "Celeron(R)", 2 }, "P-II Celeron (Covington)", "0.25 µm" }, + { 6, 6, -1, -1, -1, 1, -1, -1, { "Celeron(R)", 2 }, "P-II Celeron (Mendocino)", "0.25 µm" }, + { 6, 7, -1, -1, -1, 1, -1, -1, { "Pentium(R)", 2 }, "Pentium III (Katmai)", "0.25 µm" }, + { 6, 8, -1, -1, -1, 1, -1, -1, { "Pentium(R)", 2 }, "Pentium III (Coppermine)", "0.18 µm" }, + { 6, 10, -1, -1, -1, 1, -1, -1, { "Pentium(R)", 2 }, "Pentium III (Coppermine)", "0.18 µm" }, + { 6, 11, -1, -1, -1, 1, -1, -1, { "Pentium(R)", 2 }, "Pentium III (Tualatin)", "0.13 µm" }, + { 6, 11, -1, -1, -1, 1, 512, -1, { "Pentium(R)", 2 }, "Pentium III (Tualatin)", "0.13 µm" }, + { 6, 7, -1, -1, -1, 1, -1, -1, { "Xeon(TM)", 2 }, "P-III Xeon (Tanner)", "0.25 µm" }, + { 6, 8, -1, -1, -1, 1, -1, -1, { "Xeon(TM)", 2 }, "P-III Xeon (Cascades)", "0.18 µm" }, + { 6, 10, -1, -1, -1, 1, -1, -1, { "Xeon(TM)", 2 }, "P-III Xeon (Cascades)", "0.18 µm" }, + { 6, 11, -1, -1, -1, 1, -1, -1, { "Xeon(TM)", 2 }, "P-III Xeon (Tualatin)", "0.13 µm" }, + { 6, 7, -1, -1, -1, 1, 128, -1, { "Celeron(R)", 2 }, "P-III Celeron (Katmai)", "0.25 µm" }, + { 6, 8, -1, -1, -1, 1, 128, -1, { "Celeron(R)", 2 }, "P-III Celeron (Coppermine)", "0.18 µm" }, + { 6, 10, -1, -1, -1, 1, 128, -1, { "Celeron(R)", 2 }, "P-III Celeron (Coppermine)", "0.18 µm" }, + { 6, 11, -1, -1, -1, 1, 256, -1, { "Celeron(R)", 2 }, "P-III Celeron (Tualatin)", "0.13 µm" }, + + /* NetBurst CPUs */ + /* Willamette (2000, 180 nm): */ + { 15, 0, -1, 15, -1, 1, -1, -1, { "Pentium(R)", 2 }, "Pentium 4 (Willamette)", "0.18 µm" }, + { 15, 1, -1, 15, -1, 1, -1, -1, { "Pentium(R)", 2 }, "Pentium 4 (Willamette)", "0.18 µm" }, + { 15, 0, -1, 15, -1, 1, -1, -1, { "Pentium(R) 4 - M", 6 }, "Mobile P-4 (Willamette)", "0.18 µm" }, + { 15, 1, -1, 15, -1, 1, -1, -1, { "Pentium(R) 4 - M", 6 }, "Mobile P-4 (Willamette)", "0.18 µm" }, + { 15, 1, -1, 15, -1, 1, -1, -1, { "Celeron(R)", 2 }, "P-4 Celeron (Willamette)", "0.18 µm" }, + { 15, 0, -1, 15, -1, 1, -1, -1, { "Xeon(TM)", 2 }, "Xeon (Foster)", "0.18 µm" }, + { 15, 1, -1, 15, -1, 1, -1, -1, { "Xeon(TM)", 2 }, "Xeon (Foster)", "0.18 µm" }, + /* Northwood / Mobile Pentium 4 / Banias (2002, 130 nm): */ + { 15, 2, -1, 15, -1, 1, -1, -1, { "Pentium(R) 4", 2 }, "Pentium 4 (Northwood)", "0.13 µm" }, + { 15, 2, -1, 15, -1, 1, -1, -1, { "Pentium(R) 4 - M", 6 }, "Mobile P-4 (Northwood)", "0.13 µm" }, + { 15, 2, -1, 15, -1, 1, -1, -1, { "Celeron(R)", 2 }, "P-4 Celeron (Northwood)", "0.13 µm" }, + { 6, 9, -1, -1, -1, 1, -1, -1, { "Pentium(R)", 2 }, "Pentium M (Banias)", "0.13 µm" }, + { 6, 9, -1, -1, -1, 1, -1, -1, { "Pentium(R) 4 - M", 6 }, "Pentium M (Banias)", "0.13 µm" }, + { 6, 9, -1, -1, -1, 1, -1, -1, { "Celeron(R)", 2 }, "Celeron M (Banias)", "0.13 µm" }, + { 6, 9, -1, -1, -1, 1, -1, -1, { "Celeron(R) M", 4 }, "Celeron M (Banias)", "0.13 µm" }, + { 6, 9, -1, -1, -1, 1, 0, -1, { "Celeron(R)", 2 }, "Celeron M (Shelton)", "0.13 µm" }, + { 15, 2, -1, 15, -1, 1, -1, -1, { "Xeon(TM)", 2 }, "Xeon (Prestonia)", "0.13 µm" }, + { 15, 2, -1, 15, -1, 1, -1, -1, { "Xeon(TM) MP", 4 }, "Xeon (Gallatin)", "0.13 µm" }, + /* Prescott / Dothan (2004, 90 nm): */ + { 15, 3, -1, 15, -1, 1, -1, -1, { "Pentium(R) 4", 4 }, "Pentium 4 (Prescott)", "90 nm" }, + { 15, 4, -1, 15, -1, 1, -1, -1, { "Pentium(R) 4", 4 }, "Pentium 4 (Prescott)", "90 nm" }, + { 15, 3, -1, 15, -1, 1, -1, -1, { "Pentium(R) 4 - M", 6 }, "Mobile P-4 (Prescott)", "90 nm" }, + { 15, 4, -1, 15, -1, 1, -1, -1, { "Pentium(R) 4 - M", 6 }, "Mobile P-4 (Prescott)", "90 nm" }, + { 15, 3, -1, 15, -1, 1, -1, -1, { "Celeron(R)", 2 }, "P-4 Celeron D (Prescott)", "90 nm" }, + { 15, 4, -1, 15, -1, 1, -1, -1, { "Celeron(R)", 2 }, "P-4 Celeron D (Prescott)", "90 nm" }, + { 15, 4, -1, 15, -1, 1, -1, -1, { "Pentium(R) D", 4 }, "Pentium D (SmithField)", "90 nm" }, + { 6, 13, -1, -1, -1, 1, -1, -1, { "Pentium(R) M", 4 }, "Pentium M (Dothan)", "90 nm" }, + { 6, 13, -1, -1, -1, 1, -1, -1, { "Pentium(R) 4 - M", 6 }, "Pentium M (Dothan)", "90 nm" }, + { 6, 13, -1, -1, -1, 1, -1, -1, { "Celeron(R)", 2 }, "Celeron M (Dothan)", "90 nm" }, + { 6, 13, -1, -1, -1, 1, -1, -1, { "Celeron(R) M", 4 }, "Celeron M (Dothan)", "90 nm" }, + { 15, 3, -1, 15, -1, 1, -1, -1, { "Xeon(TM)", 2 }, "Xeon (Nocona)", "90 nm" }, + { 15, 4, -1, 15, -1, 1, -1, -1, { "Xeon(TM)", 2 }, "Xeon (Nocona)", "90 nm" }, + { 15, 4, 3, 15, -1, 1, -1, -1, { "Xeon(TM)", 2 }, "Xeon (Irwindale)", "90 nm" }, + { 15, 4, 10, 15, -1, 1, -1, -1, { "Xeon(TM)", 2 }, "Xeon (Irwindale)", "90 nm" }, + { 15, 4, 1, 15, -1, 1, -1, -1, { "Xeon(TM)", 2 }, "Xeon (Cranford)", "90 nm" }, + { 15, 4, -1, 15, -1, 1, -1, -1, { "Xeon(TM)", 2 }, "Xeon (Potomac)", "90 nm" }, + { 15, 4, 8, 15, -1, 1, -1, -1, { "Xeon(TM)", 2 }, "Xeon (Paxville)", "90 nm" }, + /* Cedar Mill / Yonah / Presler (2006, 65 nm): */ + { 15, 6, -1, 15, -1, 1, -1, -1, { "Pentium(R)", 2 }, "Pentium 4 (Cedar Mill)", "65 nm" }, + { 15, 6, -1, 15, -1, 1, -1, -1, { "Pentium(R) 4 - M", 6 }, "Mobile P-4 (Cedar Mill)", "65 nm" }, + { 15, 6, -1, 15, -1, 1, -1, -1, { "Celeron(R) D", 4 }, "P-4 Celeron D (Cedar Mill)", "65 nm" }, + { 6, 14, -1, 14, -1, 1, -1, -1, { "Core(TM) [UT]1#[05]0", 6 }, "Core Solo (Yonah)", "65 nm" }, + { 6, 14, -1, 14, -1, 1, -1, -1, { "Core(TM) 1#[05]0", 4 }, "Core Solo (Yonah)", "65 nm" }, + { 6, 14, -1, 14, -1, 2, -1, -1, { "Core(TM) Duo [UTL]2#[05]#", 6 }, "Core Duo (Yonah)", "65 nm" }, + { 6, 14, -1, 14, -1, 2, -1, -1, { "Core(TM) Duo 2#[05]#", 4 }, "Core Duo (Yonah)", "65 nm" }, + { 6, 14, -1, 14, -1, -1, -1, -1, { "Celeron(R) 215", 6 }, "Celeron (Yonah-512)", "65 nm" }, + { 6, 14, -1, 14, -1, -1, -1, -1, { "Celeron(R) M", 4 }, "Celeron (Yonah-1024)", "65 nm" }, + { 15, 6, -1, 15, -1, 1, -1, -1, { "Pentium(R) D", 4 }, "Pentium D (Presler)", "65 nm" }, + { 15, 6, 2, 15, -1, 1, -1, -1, { "Pentium(R)", 2 }, "Pentium Extreme Edition (Presler)", "65 nm" }, + { 15, 6, 4, 15, -1, 1, -1, -1, { "Xeon(TM)", 2 }, "Xeon (Dempsey)", "65 nm" }, + { 15, 6, 6, 15, -1, 1, -1, -1, { "Xeon(TM)", 2 }, "Xeon (Tulsa)", "65 nm" }, + { 15, 6, 8, 15, -1, 1, -1, -1, { "Xeon(TM)", 2 }, "Xeon (Tulsa)", "65 nm" }, + + /* Core CPUs (2006, 65 nm): https://en.wikipedia.org/wiki/Intel_Core_(microarchitecture)*/ + { 6, 15, -1, -1, -1, 2, 2048, -1, { "Core(TM)2 Duo E6###", 8 }, "Core 2 Duo (Conroe-2M)", "65 nm" }, + { 6, 15, -1, -1, -1, 2, 4096, -1, { "Core(TM)2 Duo E6###", 8 }, "Core 2 Duo (Conroe)", "65 nm" }, + { 6, 15, -1, -1, -1, 2, 4096, -1, { "Core(TM)2 6###", 4 }, "Core 2 Duo (Conroe)", "65 nm" }, + { 6, 15, -1, -1, -1, 2, 4096, -1, { "Core(TM)2 X6###", 6 }, "Core 2 Extreme (Conroe XE)", "65 nm" }, + { 6, 15, -1, -1, -1, 4, 4096, -1, { "Core(TM)2 Quad Q6###", 8 }, "Core 2 Quad (Kentsfield)", "65 nm" }, + { 6, 15, -1, -1, -1, 2, 2048, -1, { "Core(TM)2 Duo E4###", 8 }, "Core 2 Duo (Allendale)", "65 nm" }, + { 6, 15, -1, -1, 15, 2, 2048, -1, { "Core(TM)2 U7###", 6 }, "Core 2 Duo (Merom-2M)", "65 nm" }, + { 6, 15, -1, -1, 15, 2, 2048, -1, { "Core(TM)2 T[57]###", 6 }, "Core 2 Duo (Merom-2M)", "65 nm" }, + { 6, 15, -1, -1, 15, 2, 4096, -1, { "Core(TM)2 T7###", 6 }, "Core 2 Duo (Merom)", "65 nm" }, + { 6, 15, -1, -1, 15, 2, 4096, -1, { "Core(TM)2 S[LP]7###", 6 }, "Core 2 Duo (Merom)", "65 nm" }, + { 6, 15, -1, -1, 15, 2, 4096, -1, { "Core(TM)2 L7###", 6 }, "Core 2 Duo (Merom)", "65 nm" }, + { 6, 15, -1, -1, 15, 2, -1, -1, { "Pentium(R) Dual E2###", 8 }, "Pentium Dual-Core (Allendale)", "65 nm" }, + { 6, 15, -1, -1, 15, 2, -1, -1, { "Celeron(R) E1###", 6 }, "Celeron (Allendale)", "65 nm" }, + { 6, 6, -1, -1, 22, 1, -1, -1, { "Celeron(R) [24]##", 4 }, "Celeron (Conroe-L)", "65 nm" }, + { 6, 14, -1, -1, 14, 1, -1, -1, { "Xeon(R) 51##", 4 }, "Xeon LV (Woodcrest)", "65 nm" }, + { 6, 15, -1, -1, 15, 2, -1, -1, { "Xeon(R) 51##", 4 }, "Xeon (Woodcrest)", "65 nm" }, + { 6, 15, -1, -1, 15, 2, -1, -1, { "Xeon(R) 30##", 4 }, "Xeon (Conroe)", "65 nm" }, + { 6, 15, -1, -1, 15, 4, -1, -1, { "Xeon(R) X32##", 6 }, "Xeon (Kentsfield)", "65 nm" }, + { 6, 15, -1, -1, 15, 4, -1, -1, { "Xeon(R) [EXL]53##", 6 }, "Xeon (Clovertown)", "65 nm" }, + + /* Penryn CPUs (2007, 45 nm): https://en.wikipedia.org/wiki/Penryn_(microarchitecture) */ + { 6, 7, -1, -1, 23, 2, 1024, -1, { "Celeron(R) E3###", 6 }, "Celeron (Wolfdale-3M)", "45 nm" }, + { 6, 7, -1, -1, 23, 2, 1024, -1, { "Pentium(R) E2###", 6 }, "Celeron (Wolfdale-3M)", "45 nm" }, + { 6, 7, -1, -1, 23, 2, 2048, -1, { "Pentium(R) E[56]###", 6 }, "Pentium (Wolfdale-3M)", "45 nm" }, + { 6, 7, -1, -1, 23, 2, 3072, -1, { "Core(TM)2 Duo E7###", 8 }, "Core 2 Duo (Wolfdale-3M)", "45 nm" }, + { 6, 7, -1, -1, 23, 2, 6144, -1, { "Core(TM)2 Duo E8###", 8 }, "Core 2 Duo (Wolfdale)", "45 nm" }, + { 6, 7, -1, -1, 23, 2, 1024, -1, { "Pentium(R) Dual-Core T4###", 8 }, "Pentium Dual-Core (Penryn-L)", "45 nm" }, + { 6, 7, -1, -1, 23, 1, 1024, -1, { "Celeron(R) [79]##", 4 }, "Celeron (Penryn-L)", "45 nm" }, + { 6, 7, -1, -1, 23, 2, 3072, -1, { "Core(TM)2 Duo SU[78]###", 8 }, "Core 2 Duo (Penryn-3M)", "45 nm" }, + { 6, 7, -1, -1, 23, 2, 3072, -1, { "Core(TM)2 Duo P[78]###", 8 }, "Core 2 Duo (Penryn-3M)", "45 nm" }, + { 6, 7, -1, -1, 23, 2, 2048, -1, { "Core(TM)2 Duo T6###", 8 }, "Core 2 Duo (Penryn-3M)", "45 nm" }, + { 6, 7, -1, -1, 23, 2, 3072, -1, { "Core(TM)2 Duo T8###", 8 }, "Core 2 Duo (Penryn-3M)", "45 nm" }, + { 6, 7, -1, -1, 23, 2, 6144, -1, { "Core(TM)2 Duo S[LP]9###", 8 }, "Core 2 Duo (Penryn)", "45 nm" }, + { 6, 7, -1, -1, 23, 2, 6144, -1, { "Core(TM)2 Duo [PT]9###", 8 }, "Core 2 Duo (Penryn)", "45 nm" }, + { 6, 7, -1, -1, 23, 2, 6144, -1, { "Core(TM)2 Duo E8###", 8 }, "Core 2 Duo (Penryn)", "45 nm" }, + { 6, 7, -1, -1, 23, 4, 2048, -1, { "Core(TM)2 Quad Q8###", 8 }, "Core 2 Quad (Yorkfield-6M)", "45 nm" }, /* 2×2 MB L2$ */ + { 6, 7, -1, -1, 23, 4, 3072, -1, { "Core(TM)2 Quad Q9#0#", 8 }, "Core 2 Quad (Yorkfield-6M)", "45 nm" }, /* 2×3 MB L2$ */ + { 6, 7, -1, -1, 23, 4, 6144, -1, { "Core(TM)2 Quad Q9#5#", 8 }, "Core 2 Quad (Yorkfield)", "45 nm" }, /* 2×6 MB L2$ */ + { 6, 7, -1, -1, 23, 2, -1, -1, { "Xeon(R) [EL]31##", 6 }, "Xeon (Wolfdale)", "45 nm" }, + { 6, 7, -1, -1, 23, 2, -1, -1, { "Xeon(R) [EXL]52##", 6 }, "Xeon (Wolfdale DP)", "45 nm" }, + { 6, 7, -1, -1, 23, 4, -1, -1, { "Xeon(R) [EXL]54##", 6 }, "Xeon (Harpertown)", "45 nm" }, + { 6, 7, -1, -1, 23, 4, -1, -1, { "Xeon(R) [XL]33##", 6 }, "Xeon (Yorkfield)" , "45 nm" }, + { 6, 13, -1, -1, 29, -1, -1, -1, { "Xeon(R) [EXL]74##", 6 }, "Xeon (Dunnington)", "45 nm" }, + + /* Nehalem CPUs (2008, 1st Core i gen, 45 nm): https://en.wikipedia.org/wiki/Nehalem_(microarchitecture) */ + { 6, 10, -1, -1, 26, -1, -1, -1, { "Xeon(R) [WELX]5###", 6 }, "Xeon (Gainestown)", "45 nm" }, + { 6, 10, -1, -1, 26, -1, -1, -1, { "Xeon(R) [WELX]3###", 6 }, "Xeon (Bloomfield)", "45 nm" }, + { 6, 10, -1, -1, 26, -1, -1, -1, { "Core(TM) i7 9#5", 8 }, "Core i7 Extreme (Bloomfield)", "45 nm" }, + { 6, 10, -1, -1, 26, -1, -1, -1, { "Core(TM) i7 9#0", 8 }, "Core i7 (Bloomfield)", "45 nm" }, + { 6, 14, -1, -1, 30, -1, -1, -1, { "Core(TM) i7 8##", 8 }, "Core i7 (Lynnfield)", "45 nm" }, + { 6, 14, -1, -1, 30, -1, -1, -1, { "Core(TM) i5 7##", 8 }, "Core i5 (Lynnfield)", "45 nm" }, + { 6, 14, -1, -1, 30, -1, -1, -1, { "Core(TM) i7 [QX] [789]##", 10 }, "Core i7 (Clarksfield)", "45 nm" }, + { 6, 14, -1, -1, 30, -1, -1, -1, { "Core(TM) [QX] [789]##", 8 }, "Core i7 (Clarksfield)", "45 nm" }, + + /* Bonnell CPUs (2008, Atom, 45 nm): https://en.wikipedia.org/wiki/Bonnell_(microarchitecture) */ + { 6, 6, -1, -1, 38, -1, -1, -1, { "Atom(TM) E6##T", 8 }, "Atom (Tunnel Creek)", "45 nm" }, + { 6, 6, -1, -1, 38, -1, -1, -1, { "Atom(TM) E6##", 6 }, "Atom (Tunnel Creek)", "45 nm" }, + { 6, 6, -1, -1, 38, -1, -1, -1, { "Atom(TM) E6##C", 8 }, "Atom (Stellarton)", "45 nm" }, + { 6, 12, -1, -1, 28, -1, -1, -1, { "Atom(TM) Z5##", 6 }, "Atom (Silverthorne)", "45 nm" }, + { 6, 12, -1, -1, 28, -1, -1, -1, { "Atom(TM) N2##", 6 }, "Atom (Diamondville)", "45 nm" }, + { 6, 12, -1, -1, 28, -1, -1, -1, { "Atom(TM) [23]##", 6 }, "Atom (Diamondville)", "45 nm" }, + { 6, 6, -1, -1, 38, -1, -1, -1, { "Atom(TM) Z6##", 6 }, "Atom (Lincroft)", "45 nm" }, + { 6, 12, -1, -1, 28, -1, -1, -1, { "Atom(TM) Z6##", 6 }, "Atom (Lincroft)", "45 nm" }, + { 6, 12, -1, -1, 28, -1, -1, -1, { "Atom(TM) [ND][45]##", 6 }, "Atom (Pineview)", "45 nm" }, + + /* Westmere CPUs (2010, 1st Core i gen, 32 nm): https://en.wikipedia.org/wiki/Westmere_(microarchitecture) */ + { 6, 14, -1, -1, 46, -1, -1, -1, { "Xeon(R) [EXL]75##", 6 }, "Xeon 7000 (Beckton)", "32 nm" }, + { 6, 14, -1, -1, 46, -1, -1, -1, { "Xeon(R) E65##", 6 }, "Xeon 6000 (Beckton)", "32 nm" }, + { 6, 14, -1, -1, 46, -1, -1, -1, { "Xeon(R) [XELW]5[56]##", 6 }, "Xeon 5000 (Beckton)", "32 nm" }, + { 6, 14, -1, -1, 46, -1, -1, -1, { "Xeon(R) [XLW]3[456]###", 6 }, "Xeon 3000 (Beckton)", "32 nm" }, + { 6, 15, -1, -1, 47, -1, -1, -1, { "Xeon(R) E7-#8##", 6 }, "Xeon E7 (Westmere-EX)", "32 nm" }, + { 6, 12, -1, -1, 44, -1, -1, -1, { "Xeon(R) [XEL]5###", 6 }, "Xeon (Westmere-EP)", "32 nm" }, + { 6, 12, -1, -1, 44, -1, -1, -1, { "Xeon(R) W3###", 6 }, "Xeon (Gulftown)", "32 nm" }, + { 6, 12, -1, -1, 44, -1, -1, -1, { "Core(TM) i7 X 9##", 10 }, "Core i7 Extreme (Gulftown)", "32 nm" }, + { 6, 12, -1, -1, 44, -1, -1, -1, { "Core(TM) i7 9##", 8 }, "Core i7 (Gulftown)", "32 nm" }, + { 6, 5, -1, -1, 37, -1, -1, -1, { "Xeon(R) L3###", 6 }, "Xeon (Clarkdale)", "32 nm" }, + { 6, 5, -1, -1, 37, -1, -1, -1, { "Core(TM) i5 6##", 8 }, "Core i5 (Clarkdale)", "32 nm" }, + { 6, 5, -1, -1, 37, -1, -1, -1, { "Core(TM) i3 5##", 8 }, "Core i3 (Clarkdale)", "32 nm" }, + { 6, 5, -1, -1, 37, -1, -1, -1, { "Pentium(R) G6###", 6 }, "Pentium (Clarkdale)", "32 nm" }, + { 6, 5, -1, -1, 37, -1, -1, -1, { "Celeron(R) G1###", 6 }, "Celeron (Clarkdale)", "32 nm" }, + { 6, 5, -1, -1, 37, -1, -1, -1, { "Core(TM) i7 M 6##", 8 }, "Core i7 (Arrandale)", "32 nm" }, + { 6, 5, -1, -1, 37, -1, -1, -1, { "Core(TM) i5 M [45]##", 8 }, "Core i5 (Arrandale)", "32 nm" }, + { 6, 5, -1, -1, 37, -1, -1, -1, { "Core(TM) i3 M 3##", 8 }, "Core i3 (Arrandale)", "32 nm" }, + { 6, 5, -1, -1, 37, -1, -1, -1, { "Pentium(R) P6###", 6 }, "Pentium (Arrandale)", "32 nm" }, + { 6, 5, -1, -1, 37, -1, -1, -1, { "Pentium(R) 5U###", 6 }, "Pentium (Arrandale)", "32 nm" }, + { 6, 5, -1, -1, 37, -1, -1, -1, { "Celeron(R) P4###", 6 }, "Celeron (Arrandale)", "32 nm" }, + { 6, 5, -1, -1, 37, -1, -1, -1, { "Celeron(R) U3###", 6 }, "Celeron (Arrandale)", "32 nm" }, + + /* Saltwell CPUs (2011, Atom, 32 nm): https://en.wikipedia.org/wiki/Bonnell_(microarchitecture)#Third_generation_cores */ + { 6, 12, -1, -1, -1, -1, -1, -1, { "Atom(TM) [ND]2###", 6 }, "Atom (Cedarview)", "32 nm" }, + { 6, 6, -1, -1, 54, -1, -1, -1, { "Atom(TM) [ND]2###", 6 }, "Atom (Cedarview)", "32 nm" }, + { 6, 7, -1, -1, 39, -1, -1, -1, { "Atom(TM) Z2###", 6 }, "Atom (Penwell)", "32 nm" }, + + /* Sandy Bridge CPUs (2011, 2nd Core i gen, 32 nm): https://en.wikipedia.org/wiki/Sandy_Bridge */ + { 6, 10, -1, -1, 42, -1, -1, -1, { "Xeon(R) E5####[LW]", 8 }, "Xeon E5 (Sandy Bridge)", "32 nm" }, + { 6, 10, -1, -1, 42, -1, -1, -1, { "Xeon(R) E5####", 6 }, "Xeon E5 (Sandy Bridge)", "32 nm" }, + { 6, 10, -1, -1, 42, -1, -1, -1, { "Xeon(R) E3####[CL]", 8 }, "Xeon E3 (Sandy Bridge)", "32 nm" }, + { 6, 10, -1, -1, 42, -1, -1, -1, { "Xeon(R) E3####", 6 }, "Xeon E3 (Sandy Bridge)", "32 nm" }, + { 6, 10, -1, -1, 42, -1, -1, -1, { "Core(TM) i7-2###", 8 }, "Core i7 (Sandy Bridge)", "32 nm" }, + { 6, 10, -1, -1, 42, -1, -1, -1, { "Core(TM) i5-2###", 8 }, "Core i5 (Sandy Bridge)", "32 nm" }, + { 6, 10, -1, -1, 42, -1, -1, -1, { "Core(TM) i3-2###", 8 }, "Core i3 (Sandy Bridge)", "32 nm" }, + { 6, 10, -1, -1, 42, -1, -1, -1, { "Pentium(R) G[68]##", 6 }, "Pentium (Sandy Bridge)", "32 nm" }, + { 6, 10, -1, -1, 42, -1, -1, -1, { "Celeron(R) G[45]##", 6 }, "Celeron (Sandy Bridge)", "32 nm" }, + { 6, 13, -1, -1, 45, -1, -1, -1, { "Core(TM) i7-3###[KX]", 10 }, "Core i7 Extreme (Sandy Bridge-E)", "32 nm" }, + { 6, 13, -1, -1, 45, -1, -1, -1, { "Xeon(R) E5-####", 4 }, "Xeon E5 (Sandy Bridge-E)", "32 nm" }, + { 6, 13, -1, -1, 45, -1, -1, -1, { "Xeon(R) E3-####", 4 }, "Xeon E3 (Sandy Bridge-E)", "32 nm" }, + + /* Ivy Bridge CPUs (2012, 3rd Core i gen, 22 nm): https://en.wikipedia.org/wiki/Ivy_Bridge_(microarchitecture) */ + { 6, 10, -1, -1, 58, -1, -1, -1, { "Xeon(R) E7-####L v2", 8 }, "Xeon E7 (Ivy Bridge)", "22 nm" }, + { 6, 10, -1, -1, 58, -1, -1, -1, { "Xeon(R) E7-#### v2", 6 }, "Xeon E7 (Ivy Bridge)", "22 nm" }, + { 6, 10, -1, -1, 58, -1, -1, -1, { "Xeon(R) E5-####[LW] v2", 8 }, "Xeon E5 (Ivy Bridge)", "22 nm" }, + { 6, 10, -1, -1, 58, -1, -1, -1, { "Xeon(R) E5-#### v2", 6 }, "Xeon E5 (Ivy Bridge)", "22 nm" }, + { 6, 10, -1, -1, 58, -1, -1, -1, { "Xeon(R) E3-####[CL] v2", 8 }, "Xeon E3 (Ivy Bridge)", "22 nm" }, + { 6, 10, -1, -1, 58, -1, -1, -1, { "Xeon(R) E3-#### v2", 6 }, "Xeon E3 (Ivy Bridge)", "22 nm" }, + { 6, 10, -1, -1, 58, -1, -1, -1, { "Core(TM) i7-3###", 8 }, "Core i7 (Ivy Bridge)", "22 nm" }, + { 6, 10, -1, -1, 58, -1, -1, -1, { "Core(TM) i5-3###", 8 }, "Core i5 (Ivy Bridge)", "22 nm" }, + { 6, 10, -1, -1, 58, -1, -1, -1, { "Core(TM) i3-3###", 8 }, "Core i3 (Ivy Bridge)", "22 nm" }, + { 6, 10, -1, -1, 58, -1, -1, -1, { "Pentium(R) G2###", 6 }, "Pentium (Ivy Bridge)", "22 nm" }, + { 6, 10, -1, -1, 58, -1, -1, -1, { "Celeron(R) G1###", 6 }, "Celeron (Ivy Bridge)", "22 nm" }, + { 6, 14, -1, -1, 62, -1, -1, -1, { "Xeon(R) E7-#### v2", 6 }, "Xeon E7 (Ivy Bridge-E)", "22 nm" }, + { 6, 14, -1, -1, 62, -1, -1, -1, { "Xeon(R) E5-#### v2", 6 }, "Xeon E5 (Ivy Bridge-E)", "22 nm" }, + { 6, 14, -1, -1, 62, -1, -1, -1, { "Xeon(R) E3-#### v2", 6 }, "Xeon E3 (Ivy Bridge-E)", "22 nm" }, + { 6, 14, -1, -1, 62, -1, -1, -1, { "Core(TM) i7-4###X", 10 }, "Core i7 Extreme (Ivy Bridge-E)", "22 nm" }, + { 6, 14, -1, -1, 62, -1, -1, -1, { "Core(TM) i7-4###K", 8 }, "Core i7 (Ivy Bridge-E)", "22 nm" }, + + /* Silvermont CPUs (2013, Atom, 22 nm): https://en.wikipedia.org/wiki/Silvermont */ + { 6, 7, -1, -1, 55, -1, -1, -1, { "Pentium(R) J2###", 6 }, "Pentium (Bay Trail-D)", "22 nm" }, + { 6, 7, -1, -1, 55, -1, -1, -1, { "Celeron(R) J1###", 6 }, "Celeron (Bay Trail-D)", "22 nm" }, + { 6, 7, -1, -1, 55, -1, -1, -1, { "Pentium(R) N3###", 6 }, "Pentium (Bay Trail-M)", "22 nm" }, + { 6, 7, -1, -1, 55, -1, -1, -1, { "Celeron(R) N2###", 6 }, "Celeron (Bay Trail-M)", "22 nm" }, + { 6, 7, -1, -1, 55, -1, -1, -1, { "Atom(TM) Z3###", 6 }, "Atom (Bay Trail-T)", "22 nm" }, + { 6, 7, -1, -1, 55, -1, -1, -1, { "Atom(TM) E3###", 6 }, "Atom (Bay Trail-I)", "22 nm" }, + { 6, 13, -1, -1, 77, -1, -1, -1, { "Atom(TM) C2##0", 8 }, "Atom (Avoton)", "22 nm" }, + { 6, 13, -1, -1, 77, -1, -1, -1, { "Atom(TM) C2##[68]", 8 }, "Atom (Rangeley)", "22 nm" }, + + /* Haswell CPUs (2013, 4th Core i gen, 22 nm): https://en.wikipedia.org/wiki/Haswell_(microarchitecture) */ + { 6, 12, -1, -1, 60, -1, -1, -1, { "Xeon(R) E7-####L v3", 8 }, "Xeon E7 (Haswell)", "22 nm" }, + { 6, 12, -1, -1, 60, -1, -1, -1, { "Xeon(R) E7-#### v3", 6 }, "Xeon E7 (Haswell)", "22 nm" }, + { 6, 12, -1, -1, 60, -1, -1, -1, { "Xeon(R) E5-####[ABLW] v3", 8 }, "Xeon E5 (Haswell)", "22 nm" }, + { 6, 12, -1, -1, 60, -1, -1, -1, { "Xeon(R) E5-#### v3", 6 }, "Xeon E5 (Haswell)", "22 nm" }, + { 6, 12, -1, -1, 60, -1, -1, -1, { "Xeon(R) E3-####L v3", 8 }, "Xeon E3 (Haswell)", "22 nm" }, + { 6, 12, -1, -1, 60, -1, -1, -1, { "Xeon(R) E3-#### v3", 6 }, "Xeon E3 (Haswell)", "22 nm" }, + { 6, 12, -1, -1, 60, -1, -1, -1, { "Core(TM) i7-4###", 8 }, "Core i7 (Haswell)", "22 nm" }, + { 6, 12, -1, -1, 60, -1, -1, -1, { "Core(TM) i5-4###", 8 }, "Core i5 (Haswell)", "22 nm" }, + { 6, 12, -1, -1, 60, -1, -1, -1, { "Core(TM) i3-4###", 8 }, "Core i3 (Haswell)", "22 nm" }, + { 6, 12, -1, -1, 60, -1, -1, -1, { "Pentium(R) G3###", 6 }, "Pentium (Haswell)", "22 nm" }, + { 6, 12, -1, -1, 60, -1, -1, -1, { "Celeron(R) G1###", 6 }, "Celeron (Haswell)", "22 nm" }, + { 6, 15, -1, -1, 63, -1, -1, -1, { "Core(TM) i7-5###[KX]", 8 }, "Core i7 Extreme (Haswell)", "22 nm" }, + { 6, 5, -1, -1, 69, -1, -1, -1, { "Core(TM) i7-4###", 8 }, "Core i7 (Haswell)", "22 nm" }, + { 6, 5, -1, -1, 69, -1, -1, -1, { "Core(TM) i5-4###", 8 }, "Core i5 (Haswell)", "22 nm" }, + { 6, 5, -1, -1, 69, -1, -1, -1, { "Core(TM) i3-4###", 8 }, "Core i3 (Haswell)", "22 nm" }, + { 6, 6, -1, -1, 70, -1, -1, -1, { "Core(TM) i7-4###R", 10 }, "Core i7 (Haswell-H)", "22 nm" }, /* GT3e */ + { 6, 6, -1, -1, 70, -1, -1, -1, { "Core(TM) i5-4###R", 10 }, "Core i5 (Haswell-H)", "22 nm" }, /* GT3e */ + { 6, 5, -1, -1, 69, -1, -1, -1, { "Core(TM) i7-4###U", 10 }, "Core i7 (Haswell-ULT)", "22 nm" }, + { 6, 5, -1, -1, 69, -1, -1, -1, { "Core(TM) i5-4###U", 10 }, "Core i5 (Haswell-ULT)", "22 nm" }, + { 6, 5, -1, -1, 69, -1, -1, -1, { "Core(TM) i3-4###U", 10 }, "Core i3 (Haswell-ULT)", "22 nm" }, + { 6, 5, -1, -1, 69, -1, -1, -1, { "Core(TM) i7-4###Y", 10 }, "Core i7 (Haswell-ULX)", "22 nm" }, + { 6, 5, -1, -1, 69, -1, -1, -1, { "Core(TM) i5-4###Y", 10 }, "Core i5 (Haswell-ULX)", "22 nm" }, + { 6, 5, -1, -1, 69, -1, -1, -1, { "Core(TM) i3-4###Y", 10 }, "Core i3 (Haswell-ULX)", "22 nm" }, + + /* Broadwell CPUs (2014, 5th Core i gen, 14 nm): https://en.wikipedia.org/wiki/Broadwell_(microarchitecture) */ + { 6, 6, -1, -1, 86, -1, -1, -1, { "Xeon(R) D-15##", 6 }, "Xeon D (Broadwell)", "14 nm" }, + { 6, 6, -1, -1, 86, -1, -1, -1, { "Pentium(R) D15##", 6 }, "Pentium D (Broadwell)", "14 nm" }, + { 6, 7, -1, -1, 71, 4, -1, -1, { "Core(TM) i7-5###[CR]", 10 }, "Core i7 (Broadwell-H)", "14 nm" }, + { 6, 7, -1, -1, 71, 4, -1, -1, { "Core(TM) i5-5###[CR]", 10 }, "Core i5 (Broadwell-H)", "14 nm" }, + { 6, 13, -1, -1, 61, 4, -1, -1, { "Core(TM) i7-5###HQ", 12 }, "Core i7 (Broadwell-U)", "14 nm" }, + { 6, 13, -1, -1, 61, 2, -1, -1, { "Core(TM) i7-5###U", 10 }, "Core i7 (Broadwell-U)", "14 nm" }, + { 6, 13, -1, -1, 61, 2, -1, -1, { "Core(TM) i5-5###[HU]", 10 }, "Core i5 (Broadwell-U)", "14 nm" }, + { 6, 13, -1, -1, 61, 2, -1, -1, { "Core(TM) i3-5###U", 10 }, "Core i3 (Broadwell-U)", "14 nm" }, + { 6, 13, -1, -1, 61, 2, -1, -1, { "Pentium(R) 3###U", 6 }, "Pentium (Broadwell-U)", "14 nm" }, + { 6, 13, -1, -1, 61, 2, -1, -1, { "Celeron(R) 3###U", 6 }, "Celeron (Broadwell-U)", "14 nm" }, + { 6, 13, -1, -1, 61, 2, -1, -1, { "5Y##", 4 }, "Core M (Broadwell-Y)", "14 nm" }, + { 6, 15, -1, -1, 79, -1, -1, -1, { "Xeon(R) E7-#### v4", 6 }, "Xeon E7 (Broadwell)", "14 nm" }, + { 6, 15, -1, -1, 79, -1, -1, -1, { "Xeon(R) E5-####[ACLPRW] v4", 8 }, "Xeon E5 (Broadwell)", "14 nm" }, + { 6, 15, -1, -1, 79, -1, -1, -1, { "Xeon(R) E5-#### v4", 6 }, "Xeon E5 (Broadwell)", "14 nm" }, + { 6, 15, -1, -1, 79, -1, -1, -1, { "Xeon(R) E3-####L v4", 8 }, "Xeon E3 (Broadwell)", "14 nm" }, + { 6, 15, -1, -1, 79, -1, -1, -1, { "Xeon(R) E3-#### v4", 6 }, "Xeon E3 (Broadwell)", "14 nm" }, + { 6, 15, -1, -1, 79, 4, -1, -1, { "Core(TM) i7-6###[KX]", 10 }, "Core i7 (Broadwell-E)", "14 nm" }, + + /* Airmont CPUs (2014, Atom, 14 nm): https://en.wikipedia.org/wiki/Silvermont#List_of_Airmont_processors */ + { 6, 12, -1, -1, 76, -1, -1, -1, { "Pentium(R) [JN]3###", 6 }, "Pentium (Braswell)", "14 nm" }, + { 6, 12, -1, -1, 76, -1, -1, -1, { "Celeron(R) [JN]3###", 6 }, "Celeron (Braswell)", "14 nm" }, + { 6, 12, -1, -1, 76, 4, -1, -1, { "Atom(TM) x7-Z8###", 8 }, "Atom x7 (Cherry Trail)", "14 nm" }, + { 6, 12, -1, -1, 76, 4, -1, -1, { "Atom(TM) x5-Z8###", 8 }, "Atom x5 (Cherry Trail)", "14 nm" }, + { 6, 5, -1, -1, 117, -1, -1, -1, { "Spreadtrum", 2 }, "Spreadtrum (Airmont)", "14 nm" }, /* Spreadtrum SC9853I-IA */ + + /* Skylake (client) CPUs (2015, 6th Core i gen, 14 nm): https://en.wikichip.org/wiki/intel/microarchitectures/skylake_(client) */ + { 6, 14, -1, -1, 94, 4, -1, -1, { "Core(TM) i7-6###", 8 }, "Core i7 (Skylake)", "14 nm" }, + { 6, 14, -1, -1, 94, 4, -1, -1, { "Core(TM) i5-6###", 8 }, "Core i5 (Skylake)", "14 nm" }, + { 6, 14, -1, -1, 94, 2, -1, -1, { "Core(TM) i3-6###", 8 }, "Core i3 (Skylake)", "14 nm" }, + { 6, 14, -1, -1, 94, 2, -1, -1, { "Pentium(R) G4###", 6 }, "Pentium (Skylake)", "14 nm" }, + { 6, 14, -1, -1, 94, 2, -1, -1, { "Celeron(R) G3###", 6 }, "Celeron (Skylake)", "14 nm" }, + { 6, 14, -1, -1, 78, 2, -1, -1, { "Core(TM) m7-6Y##", 8 }, "Core m7 (Skylake)", "14 nm" }, + { 6, 14, -1, -1, 78, 2, -1, -1, { "Core(TM) m5-6Y##", 8 }, "Core m5 (Skylake)", "14 nm" }, + { 6, 14, -1, -1, 78, 2, -1, -1, { "Core(TM) m3-6Y##", 8 }, "Core m3 (Skylake)", "14 nm" }, + { 6, 14, -1, -1, 78, 2, -1, -1, { "Pentium(R) 4###[UY]", 6 }, "Pentium (Skylake)", "14 nm" }, + { 6, 14, -1, -1, 78, 2, -1, -1, { "Celeron(R) 3###U", 6 }, "Celeron (Skylake)", "14 nm" }, + { 6, 14, -1, -1, 78, 2, -1, -1, { "Celeron(R) G3###E", 8 }, "Celeron (Skylake)", "14 nm" }, + { 6, 5, -1, -1, 85, -1, -1, -1, { "Core(TM) i9-7###X", 10 }, "Core i9 (Skylake-X)", "14 nm" }, + { 6, 5, -1, -1, 85, -1, -1, -1, { "Core(TM) i7-7###X", 10 }, "Core i7 (Skylake-X)", "14 nm" }, /* Core i7 7800X + 7820X */ + { 6, 5, -1, -1, 85, -1, -1, -1, { "Core(TM) i9-9###X", 10 }, "Core i9 (Skylake-X)", "14 nm" }, + { 6, 5, -1, -1, 85, -1, -1, -1, { "Core(TM) i7-9###X", 10 }, "Core i7 (Skylake-X)", "14 nm" }, /* Core i7 9800X */ + { 6, 14, -1, -1, 94, -1, -1, -1, { "Xeon(R) W-#1##X", 8 }, "Xeon (Skylake-X)", "14 nm" }, + /* Skylake (server) CPUs (2017, 1st Xeon Scalable gen, 14 nm): https://en.wikichip.org/wiki/intel/microarchitectures/skylake_(server) */ + { 6, 5, -1, -1, 85, -1, -1, -1, { "Xeon(R) D-#1##", 6 }, "Xeon D (Skylake-D)", "14 nm" }, + { 6, 5, -1, -1, 85, -1, -1, -1, { "Xeon(R) E3-####[ML] v5", 8 }, "Xeon E3 (Skylake-S)", "14 nm" }, + { 6, 5, -1, -1, 85, -1, -1, -1, { "Xeon(R) E3-#### v5", 6 }, "Xeon E3 (Skylake-S)", "14 nm" }, + { 6, 5, -1, -1, 85, -1, -1, -1, { "Xeon(R) W-#1##", 6 }, "Xeon W (Skylake-W)", "14 nm" }, + { 6, 5, -1, -1, 85, -1, -1, -1, { "Xeon(R) Platinum #1##", 6 }, "Xeon Platinum (Skylake-SP)", "14 nm" }, + { 6, 5, -1, -1, 85, -1, -1, -1, { "Xeon(R) Gold #1##", 6 }, "Xeon Gold (Skylake-SP)", "14 nm" }, + { 6, 5, -1, -1, 85, -1, -1, -1, { "Xeon(R) Silver #1##", 6 }, "Xeon Silver (Skylake-SP)", "14 nm" }, + { 6, 5, -1, -1, 85, -1, -1, -1, { "Xeon(R) Bronze #1##", 6 }, "Xeon Bronze (Skylake-SP)", "14 nm" }, + { 6, 5, -1, -1, 85, -1, -1, -1, { "Montage(R) Jintide(R)", 4 }, "Jintide (Skylake-SP)", "14 nm" }, /* Montage(R) Jintide(R) C2460 */ + /* Kaby Lake CPUs (2016, 7th Core i gen, 14+ nm): https://en.wikipedia.org/wiki/Kaby_Lake */ + { 6, 14, -1, -1, 158, 4, -1, -1, { "Core(TM) i7-7###", 8 }, "Core i7 (Kaby Lake)", "14+ nm" }, + { 6, 14, -1, -1, 158, 4, -1, -1, { "Core(TM) i5-7###", 8 }, "Core i5 (Kaby Lake)", "14+ nm" }, + { 6, 14, -1, -1, 158, 2, -1, -1, { "Core(TM) i3-7###", 8 }, "Core i3 (Kaby Lake)", "14+ nm" }, + { 6, 14, -1, -1, 158, 2, -1, -1, { "Pentium(R) G4###", 6 }, "Pentium (Kaby Lake)", "14+ nm" }, + { 6, 14, -1, -1, 158, 2, -1, -1, { "Celeron(R) G3###", 6 }, "Celeron (Kaby Lake)", "14+ nm" }, + { 6, 14, -1, -1, 158, 4, -1, -1, { "Core(TM) i7-7###X", 10 }, "Core i7 (Kaby Lake-X)", "14+ nm" }, + { 6, 14, -1, -1, 158, 4, -1, -1, { "Core(TM) i5-7###X", 10 }, "Core i5 (Kaby Lake-X)", "14+ nm" }, + { 6, 14, -1, -1, 142, 2, -1, -1, { "Core(TM) i7-7.##", 8 }, "Core i7 (Kaby Lake-U)", "14+ nm" }, + { 6, 14, -1, -1, 142, 2, -1, -1, { "Core(TM) i5-7.##", 8 }, "Core i5 (Kaby Lake-U)", "14+ nm" }, + { 6, 14, -1, -1, 142, 2, -1, -1, { "Core(TM) i3-7.##", 8 }, "Core i3 (Kaby Lake-U)", "14+ nm" }, + { 6, 14, -1, -1, 142, 2, -1, -1, { "Core(TM) m3-7.##", 8 }, "Core m3 (Kaby Lake-U)", "14+ nm" }, + { 6, 14, -1, -1, 142, 2, -1, -1, { "Pentium(R) 441#[UY]", 8 }, "Pentium Gold (Kaby Lake-U)", "14+ nm" }, + { 6, 14, -1, -1, 142, 2, -1, -1, { "Celeron(R) 3###[UY]", 6 }, "Celeron (Kaby Lake-U)", "14+ nm" }, + { 6, 14, -1, -1, 158, 4, -1, -1, { "Core(TM) i7-8###G", 10 }, "Core i7 (Kaby Lake-G)", "14+ nm" }, + { 6, 14, -1, -1, 158, 4, -1, -1, { "Core(TM) i5-8###G", 10 }, "Core i5 (Kaby Lake-G)", "14+ nm" }, + { 6, 14, -1, -1, 142, 4, -1, -1, { "Core(TM) i7-8##0U", 10 }, "Core i7 (Kaby Lake-R)", "14+ nm" }, /* i7-8550U + i7-8650U */ + { 6, 14, -1, -1, 142, 4, -1, -1, { "Core(TM) i5-8##0U", 10 }, "Core i5 (Kaby Lake-R)", "14+ nm" }, /* i5-8250U + i5-8350U */ + { 6, 14, -1, -1, 142, 2, -1, -1, { "Core(TM) i3-8##0U", 10 }, "Core i3 (Kaby Lake-R)", "14+ nm" }, /* i3-8130U */ + { 6, 14, -1, -1, 142, 2, -1, -1, { "Pentium(R) 4###U", 6 }, "Pentium Gold (Kaby Lake-R)", "14+ nm" }, /* Pentium 4417U */ + { 6, 14, -1, -1, 142, 2, -1, -1, { "Celeron(R) 3###U", 6 }, "Celeron (Kaby Lake-R)", "14+ nm" }, /* Celeron 3867U */ + /* Coffee Lake CPUs (2017, 8th Core i gen, 14++ nm): https://en.wikipedia.org/wiki/Coffee_Lake */ + { 6, 14, -1, -1, 158, 6, -1, -1, { "Core(TM) i7-8###", 8 }, "Core i7 (Coffee Lake-S)", "14++ nm" }, + { 6, 14, -1, -1, 158, 6, -1, -1, { "Core(TM) i5-8###", 8 }, "Core i5 (Coffee Lake-S)", "14++ nm" }, + { 6, 14, -1, -1, 158, 4, -1, -1, { "Core(TM) i3-8###", 8 }, "Core i3 (Coffee Lake-S)", "14++ nm" }, + { 6, 14, -1, -1, 158, 2, -1, -1, { "Pentium(R) G5###", 6 }, "Pentium Gold (Coffee Lake-S)", "14++ nm" }, + { 6, 14, -1, -1, 158, 2, -1, -1, { "Celeron(R) G4###", 6 }, "Celeron (Coffee Lake-S)", "14++ nm" }, + { 6, 14, -1, -1, 158, 6, -1, -1, { "Xeon(R) E-21##M", 8 }, "Xeon E (Coffee Lake-H)", "14++ nm" }, + { 6, 14, -1, -1, 158, 6, -1, -1, { "Core(TM) i9-8###[HB]", 10 }, "Core i9 (Coffee Lake-H)", "14++ nm" }, + { 6, 14, -1, -1, 158, 6, -1, -1, { "Core(TM) i7-8###[HB]", 10 }, "Core i7 (Coffee Lake-H)", "14++ nm" }, + { 6, 14, -1, -1, 158, 4, -1, -1, { "Core(TM) i5-8###[HB]", 10 }, "Core i5 (Coffee Lake-H)", "14++ nm" }, + { 6, 14, -1, -1, 158, 4, -1, -1, { "Core(TM) i5-8###[HB]", 10 }, "Core i5 (Coffee Lake-H)", "14++ nm" }, + { 6, 14, -1, -1, 158, 4, -1, -1, { "Core(TM) i3-8###[HB]", 10 }, "Core i3 (Coffee Lake-H)", "14++ nm" }, + { 6, 14, -1, -1, 158, 4, -1, -1, { "Core(TM) i7-8###U", 10 }, "Core i7 (Coffee Lake-U)", "14++ nm" }, + { 6, 14, -1, -1, 158, 4, -1, -1, { "Core(TM) i5-8###U", 10 }, "Core i5 (Coffee Lake-U)", "14++ nm" }, + { 6, 14, -1, -1, 158, 2, -1, -1, { "Core(TM) i3-8###U", 10 }, "Core i3 (Coffee Lake-U)", "14++ nm" }, + /* Coffee Lake Refresh CPUs (2018, 9th Core i gen, 14++ nm): https://en.wikipedia.org/wiki/Coffee_Lake#List_of_9th_generation_Coffee_Lake_processors_(Coffee_Lake_Refresh) */ + { 6, 14, -1, -1, 158, 8, -1, -1, { "Xeon(R) E-2###", 6 }, "Xeon E (Coffee Lake-S WS)", "14++ nm" }, + { 6, 14, -1, -1, 158, 8, -1, -1, { "CC###", 4 }, "CC (Coffee Lake)", "14++ nm" }, /* CC150 */ + { 6, 14, -1, -1, 158, 8, -1, -1, { "Core(TM) i9-9###", 8 }, "Core i9 (Coffee Lake-S)", "14++ nm" }, + { 6, 14, -1, -1, 158, 8, -1, -1, { "Core(TM) i7-9###", 8 }, "Core i7 (Coffee Lake-S)", "14++ nm" }, + { 6, 14, -1, -1, 158, 6, -1, -1, { "Core(TM) i5-9###", 8 }, "Core i5 (Coffee Lake-S)", "14++ nm" }, + { 6, 14, -1, -1, 158, 4, -1, -1, { "Core(TM) i3-9###", 8 }, "Core i3 (Coffee Lake-S)", "14++ nm" }, + { 6, 14, -1, -1, 158, 2, -1, -1, { "Pentium(R) Gold G5###", 8 }, "Pentium Gold (Coffee Lake-S)", "14++ nm" }, + { 6, 14, -1, -1, 158, 2, -1, -1, { "Celeron(R) G4###", 6 }, "Celeron (Coffee Lake-S)", "14++ nm" }, + { 6, 14, -1, -1, 158, -1, -1, -1, { "Xeon(R) E-22##M", 8 }, "Xeon E (Coffee Lake-H Refresh)", "14++ nm" }, + { 6, 14, -1, -1, 158, 8, -1, -1, { "Core(TM) i9-9###H", 10 }, "Core i9 (Coffee Lake-H Refresh)", "14++ nm" }, + { 6, 14, -1, -1, 158, 6, -1, -1, { "Core(TM) i7-9###H", 10 }, "Core i7 (Coffee Lake-H Refresh)", "14++ nm" }, + { 6, 14, -1, -1, 158, 4, -1, -1, { "Core(TM) i5-9###H", 10 }, "Core i5 (Coffee Lake-H Refresh)", "14++ nm" }, + /* Whiskey Lake CPUs (2018, 8th Core i gen, 14++ nm): https://en.wikipedia.org/wiki/Whiskey_Lake */ + { 6, 14, -1, -1, 142, 4, -1, -1, { "Core(TM) i7-8##5U", 10 }, "Core i7 (Whiskey Lake-U)", "14++ nm" }, + { 6, 14, -1, -1, 142, 4, -1, -1, { "Core(TM) i5-8##5U", 10 }, "Core i5 (Whiskey Lake-U)", "14++ nm" }, + { 6, 14, -1, -1, 142, 2, -1, -1, { "Core(TM) i3-8##5U", 10 }, "Core i3 (Whiskey Lake-U)", "14++ nm" }, + { 6, 14, -1, -1, 142, 2, -1, -1, { "Pentium(R) 5###U", 6 }, "Pentium Gold (Whiskey Lake-U)", "14++ nm" }, + { 6, 14, -1, -1, 142, 2, -1, -1, { "Celeron(R) 4###U", 6 }, "Celeron (Whiskey Lake-U)", "14++ nm" }, + /* Amber Lake CPUs (2018, 8th Core i gen, 14++ nm): https://en.wikipedia.org/wiki/Kaby_Lake#Amber_Lake */ + { 6, 14, -1, -1, 142, 4, -1, -1, { "Core(TM) i7-8###Y", 10 }, "Core i7 (Amber Lake-Y)", "14+ nm" }, /* i7-8500Y */ + { 6, 14, -1, -1, 142, 4, -1, -1, { "Core(TM) i5-8###Y", 10 }, "Core i5 (Amber Lake-Y)", "14+ nm" }, /* i5-8200Y + i5-82010Y + i5-8310Y */ + { 6, 14, -1, -1, 142, 2, -1, -1, { "Core(TM) m3-8###Y", 10 }, "Core m3 (Amber Lake-Y)", "14+ nm" }, /* m3-8100Y */ + { 6, 14, -1, -1, 142, 2, -1, -1, { "Pentium(R) 442#Y", 8 }, "Pentium Gold (Amber Lake-Y)", "14+ nm" }, /* Pentium 4425Y */ + { 6, 14, -1, -1, 142, 4, -1, -1, { "Core(TM) i7-10###Y", 10 }, "Core i7 (Amber Lake-Y)", "14+ nm" }, /* i7-10510Y */ + { 6, 14, -1, -1, 142, 4, -1, -1, { "Core(TM) i5-10###Y", 10 }, "Core i5 (Amber Lake-Y)", "14+ nm" }, /* i5-10210Y + i5-10310Y + i5-8310Y */ + { 6, 14, -1, -1, 142, 2, -1, -1, { "Core(TM) i3-10###Y", 10 }, "Core i3 (Amber Lake-Y)", "14+ nm" }, /* i3-10100Y + i3-10110Y */ + { 6, 14, -1, -1, 142, 2, -1, -1, { "Pentium(R) 65##Y", 6 }, "Pentium Gold (Amber Lake-Y)", "14+ nm" }, /* Pentium 6500Y */ + /* Cascade Lake CPUs (2019, 2nd Xeon Scalable gen, 14++ nm): https://en.wikichip.org/wiki/intel/microarchitectures/cascade_lake */ + { 6, 5, 7, -1, 85, -1, -1, -1, { "Core(TM) i9-10###X", 10 }, "Core i9 (Cascade Lake-X)", "14++ nm" }, + { 6, 5, -1, -1, 85, -1, -1, -1, { "Xeon(R) W-#[23]##", 6 }, "Xeon W (Cascade Lake-W)", "14++ nm" }, + { 6, 5, -1, -1, 85, -1, -1, -1, { "Xeon(R) Platinum #2##", 6 }, "Xeon Platinum (Cascade Lake-SP)", "14++ nm" }, + { 6, 5, -1, -1, 85, -1, -1, -1, { "Xeon(R) Gold #2##", 6 }, "Xeon Gold (Cascade Lake-SP)", "14++ nm" }, + { 6, 5, -1, -1, 85, -1, -1, -1, { "Xeon(R) Silver #2##", 6 }, "Xeon Silver (Cascade Lake-SP)", "14++ nm" }, + { 6, 5, -1, -1, 85, -1, -1, -1, { "Xeon(R) Bronze #2##", 6 }, "Xeon Bronze (Cascade Lake-SP)", "14++ nm" }, + /* Comet Lake CPUs (2019, 10th Core i gen, 14++ nm): https://en.wikipedia.org/wiki/Comet_Lake */ + { 6, 5, -1, -1, 165, -1, -1, -1, { "Xeon(R) W-12##", 6 }, "Xeon W (Comet Lake-S)", "14++ nm" }, + { 6, 5, -1, -1, 165, 10, -1, -1, { "Core(TM) i9-10###", 8 }, "Core i9 (Comet Lake-S)", "14++ nm" }, + { 6, 5, -1, -1, 165, 8, -1, -1, { "Core(TM) i7-10###", 8 }, "Core i7 (Comet Lake-S)", "14++ nm" }, + { 6, 5, -1, -1, 165, 6, -1, -1, { "Core(TM) i5-10###", 8 }, "Core i5 (Comet Lake-S)", "14++ nm" }, + { 6, 5, -1, -1, 165, 4, -1, -1, { "Core(TM) i3-10###", 8 }, "Core i3 (Comet Lake-S)", "14++ nm" }, + { 6, 5, -1, -1, 165, 2, -1, -1, { "Pentium(R) Gold G6###", 8 }, "Pentium Gold (Comet Lake-S)", "14++ nm" }, + { 6, 5, -1, -1, 165, 2, -1, -1, { "Celeron(R) G5###", 6 }, "Celeron (Comet Lake-S)", "14++ nm" }, + { 6, 6, -1, -1, 166, 6, -1, -1, { "Core(TM) i7-10###U", 10 }, "Core i7 (Comet Lake-U)", "14++ nm" }, + { 6, 14, 12, -1, 142, 6, -1, -1, { "Core(TM) i7-10###U", 10 }, "Core i7 (Comet Lake-U)", "14++ nm" }, + { 6, 14, 12, -1, 142, 4, -1, -1, { "Core(TM) i7-10###U", 10 }, "Core i7 (Comet Lake-U)", "14++ nm" }, + { 6, 14, 12, -1, 142, 4, -1, -1, { "Core(TM) i5-10###U", 10 }, "Core i5 (Comet Lake-U)", "14++ nm" }, + { 6, 14, 12, -1, 142, 4, -1, -1, { "Core(TM) i3-10###U", 10 }, "Core i3 (Comet Lake-U)", "14++ nm" }, + { 6, 14, 12, -1, 142, 2, -1, -1, { "Pentium(R) Gold 6###U", 8 }, "Pentium Gold (Comet Lake-U)", "14++ nm" }, + { 6, 14, 12, -1, 142, 2, -1, -1, { "Celeron(R) 5###U", 6 }, "Celeron (Comet Lake-U)", "14++ nm" }, + { 6, 5, -1, -1, 165, -1, -1, -1, { "Xeon(R) W-10###M", 10 }, "Xeon W (Comet Lake-H)", "14++ nm" }, + { 6, 5, -1, -1, 165, -1, -1, -1, { "Core(TM) i9-10###H", 10 }, "Core i9 (Comet Lake-H)", "14++ nm" }, + { 6, 5, -1, -1, 165, -1, -1, -1, { "Core(TM) i7-10###H", 10 }, "Core i7 (Comet Lake-H)", "14++ nm" }, + { 6, 5, -1, -1, 165, -1, -1, -1, { "Core(TM) i5-10###H", 10 }, "Core i5 (Comet Lake-H)", "14++ nm" }, + + /* Goldmont CPUs (2016, Atom, 14 nm): https://en.wikipedia.org/wiki/Goldmont */ + { 6, 12, -1, -1, 92, -1, -1, -1, { "Pentium(R) J4###", 6 }, "Pentium (Apollo Lake)", "14 nm" }, + { 6, 12, -1, -1, 92, -1, -1, -1, { "Celeron(R) J3###", 6 }, "Celeron (Apollo Lake)", "14 nm" }, + { 6, 12, -1, -1, 92, -1, -1, -1, { "Pentium(R) N4###", 6 }, "Pentium (Apollo Lake)", "14 nm" }, + { 6, 12, -1, -1, 92, -1, -1, -1, { "Celeron(R) N3###", 6 }, "Celeron (Apollo Lake)", "14 nm" }, + { 6, 12, -1, -1, 92, -1, -1, -1, { "Atom(TM) E39##", 6 }, "Atom (Apollo Lake)", "14 nm" }, + { 6, 15, -1, -1, 95, -1, -1, -1, { "Atom(TM) C39##", 6 }, "Atom (Denverton)" , "14 nm" }, + + /* Goldmont Plus CPUs (2017, Atom, 14 nm): https://en.wikipedia.org/wiki/Goldmont_Plus */ + { 6, 10, -1, -1, 122, -1, -1, -1, { "Pentium(R) Silver [JN]5###", 8 }, "Pentium Silver (Gemini Lake)", "14 nm" }, + { 6, 10, -1, -1, 122, -1, -1, -1, { "Celeron(R) [JN]4###", 6 }, "Celeron (Gemini Lake)", "14 nm" }, + + /* Palm Cove CPUs (2018, 8th Core i gen, 14++ nm): https://en.wikipedia.org/wiki/Cannon_Lake_(microprocessor)*/ + { 6, 6, -1, -1, 102, 2, -1, -1, { "Core(TM) i3-8###U", 10 }, "Core i3 (Cannon Lake-U)", "14++ nm" }, /* Core i3 8121U */ + { 6, 6, -1, -1, 102, 2, -1, -1, { "Core(TM) m3-8###Y", 10 }, "Core m3 (Cannon Lake-Y)", "14++ nm" }, /* Core m3 8114Y */ + + /* Sunny Cove CPUs (2019, 10th Core i gen, 10 nm): https://en.wikipedia.org/wiki/Sunny_Cove_(microarchitecture) */ + { 6, 14, -1, -1, 126, 4, -1, -1, { "Core(TM) i7-10##NG7", 10 }, "Core i7 (Ice Lake)", "10 nm" }, + { 6, 14, -1, -1, 126, 4, -1, -1, { "Core(TM) i7-10##G7", 10 }, "Core i7 (Ice Lake)", "10 nm" }, + { 6, 14, -1, -1, 126, 4, -1, -1, { "Core(TM) i5-10##NG7", 10 }, "Core i5 (Ice Lake)", "10 nm" }, + { 6, 14, -1, -1, 126, 4, -1, -1, { "Core(TM) i5-10##G[741]", 10 }, "Core i5 (Ice Lake)", "10 nm" }, + { 6, 14, -1, -1, 126, 2, -1, -1, { "Core(TM) i3-10##G[14]", 10 }, "Core i3 (Ice Lake)", "10 nm" }, + { 6, 14, -1, -1, 126, 2, -1, -1, { "Core(TM) i3-10##NG4", 10 }, "Core i3 (Ice Lake)", "10 nm" }, + { 6, 14, -1, -1, 126, 2, -1, -1, { "Pentium(R) 68##", 4 }, "Pentium (Ice Lake)", "10 nm" }, /* Pentium 6805 */ + /* Ice Lake (server) CPUs (2021, 3rd Xeon Scalable gen, 10 nm): https://en.wikichip.org/wiki/intel/microarchitectures/ice_lake_(server) */ + { 6, 12, -1, -1, 108, -1, -1, -1, { "Xeon(R) D-[12]7##", 6 }, "Xeon D (Ice Lake-D)", "10 nm" }, + { 6, 10, -1, -1, 106, -1, -1, -1, { "Xeon(R) W-#3##", 6 }, "Xeon W (Ice Lake-W)", "10 nm" }, + { 6, 10, -1, -1, 106, -1, -1, -1, { "Xeon(R) Platinum #3##", 6 }, "Xeon Platinum (Ice Lake-SP)", "10 nm" }, + { 6, 10, -1, -1, 106, -1, -1, -1, { "Xeon(R) Gold #3##", 6 }, "Xeon Gold (Ice Lake-SP)", "10 nm" }, + { 6, 10, -1, -1, 106, -1, -1, -1, { "Xeon(R) Silver #3##", 6 }, "Xeon Silver (Ice Lake-SP)", "10 nm" }, + { 6, 10, -1, -1, 106, -1, -1, -1, { "Xeon(R) Bronze #3##", 6 }, "Xeon Bronze (Ice Lake-SP)", "10 nm" }, + + /* Tremont CPUs (2020, Atom, 10 nm): https://en.wikipedia.org/wiki/Tremont_(microarchitecture) */ + { 6, 6, -1, -1, 150, -1, -1, -1, { "Pentium(R) [JN]6###", 6 }, "Pentium (Elkhart Lake)", "10 nm" }, + { 6, 6, -1, -1, 150, -1, -1, -1, { "Celeron(R) [JN]6###", 6 }, "Celeron (Elkhart Lake)", "10 nm" }, + { 6, 6, -1, -1, 150, -1, -1, -1, { "Atom(TM) x6###", 6 }, "Atom (Elkhart Lake)", "10 nm" }, + { 6, 10, -1, -1, 138, -1, -1, -1, { "Core(TM) i5-L##G7", 12 }, "Core i5 (Lakefield)", "10 nm" }, + { 6, 10, -1, -1, 138, -1, -1, -1, { "Core(TM) i3-L##G4", 12 }, "Core i3 (Lakefield)", "10 nm" }, + { 6, 12, -1, -1, 156, -1, -1, -1, { "Pentium(R) Silver N6###", 8 }, "Pentium Silver (Jasper Lake)", "10 nm" }, + { 6, 12, -1, -1, 156, -1, -1, -1, { "Celeron(R) N[45]###", 6 }, "Celeron (Jasper Lake)", "10 nm" }, + + /* Willow Cove CPUs (2020, 11th Core i gen, 10 nm SuperFin): https://en.wikipedia.org/wiki/Willow_Cove */ + { 6, 12, -1, -1, 140, -1, -1, -1, { "Core(TM) i7-11#5G7", 12 }, "Core i7 (Tiger Lake-UP3)", "10SF" }, + { 6, 12, -1, -1, 140, -1, -1, -1, { "Core(TM) i5-11#5G7", 12 }, "Core i5 (Tiger Lake-UP3)", "10SF" }, + { 6, 12, -1, -1, 140, -1, -1, -1, { "Core(TM) i3-11#5G4", 12 }, "Core i3 (Tiger Lake-UP3)", "10SF" }, + { 6, 12, -1, -1, 140, 2, -1, -1, { "Pentium(R) Gold 7##5", 6 }, "Pentium Gold (Tiger Lake-UP3)", "10SF" }, + { 6, 12, -1, -1, 140, 2, -1, -1, { "Celeron(R) 6##5", 4 }, "Celeron (Tiger Lake-UP3)", "10SF" }, + { 6, 12, -1, -1, 140, -1, -1, -1, { "Core(TM) i7-11#0G7", 12 }, "Core i7 (Tiger Lake-UP4)", "10SF" }, + { 6, 12, -1, -1, 140, -1, -1, -1, { "Core(TM) i5-11#0G7", 12 }, "Core i5 (Tiger Lake-UP4)", "10SF" }, + { 6, 12, -1, -1, 140, -1, -1, -1, { "Core(TM) i3-11#0G4", 12 }, "Core i3 (Tiger Lake-UP4)", "10SF" }, + { 6, 12, -1, -1, 140, -1, -1, -1, { "Core(TM) i7-11###H", 10 }, "Core i7 (Tiger Lake-H35)", "10SF" }, + { 6, 12, -1, -1, 140, -1, -1, -1, { "Core(TM) i5-11###H", 10 }, "Core i5 (Tiger Lake-H35)", "10SF" }, + { 6, 13, -1, -1, 141, -1, -1, -1, { "Xeon(R) W-11###M", 10 }, "Xeon W (Tiger Lake-H)", "10SF" }, + { 6, 13, -1, -1, 141, -1, -1, -1, { "Core(TM) i9-11###H", 10 }, "Core i9 (Tiger Lake-H)", "10SF" }, + { 6, 13, -1, -1, 141, -1, -1, -1, { "Core(TM) i7-11###H", 10 }, "Core i7 (Tiger Lake-H)", "10SF" }, + { 6, 13, -1, -1, 141, -1, -1, -1, { "Core(TM) i5-11###H", 10 }, "Core i5 (Tiger Lake-H)", "10SF" }, + { 6, 13, -1, -1, 141, -1, -1, -1, { "Core(TM) i9-11###KB", 12 }, "Core i9 (Tiger Lake-B)", "10SF" }, /* i9-11900KB */ + { 6, 13, -1, -1, 141, -1, -1, -1, { "Core(TM) i7-11###B", 10 }, "Core i7 (Tiger Lake-B)", "10SF" }, /* i7-11700B */ + { 6, 13, -1, -1, 141, -1, -1, -1, { "Core(TM) i5-11###B", 10 }, "Core i5 (Tiger Lake-B)", "10SF" }, /* i5-11500B */ + { 6, 13, -1, -1, 141, -1, -1, -1, { "Core(TM) i5-11###B", 10 }, "Core i5 (Tiger Lake-B)", "10SF" }, /* i3-11100B */ + + /* Cypress Cove CPUs (2021, 11th Core i gen, 14++ nm): https://en.wikipedia.org/wiki/Sunny_Cove_(microarchitecture)#Cypress_Cove */ + { 6, 7, -1, -1, 167, -1, -1, -1, { "Core(TM) i9-11###", 8 }, "Core i9 (Rocket Lake-S)", "14++ nm" }, + { 6, 7, -1, -1, 167, -1, -1, -1, { "Core(TM) i7-11###", 8 }, "Core i7 (Rocket Lake-S)", "14++ nm" }, + { 6, 7, -1, -1, 167, -1, -1, -1, { "Core(TM) i5-11###", 8 }, "Core i5 (Rocket Lake-S)", "14++ nm" }, + { 6, 7, -1, -1, 167, -1, -1, -1, { "Xeon(R) E-23##", 6 }, "Xeon E (Rocket Lake)" , "14++ nm" }, + + /* Golden Cove (P-cores) / Gracemont (E-cores) CPUs (2021, 12th Core i gen, Intel 7): https://en.wikipedia.org/wiki/Golden_Cove */ + { 6, 7, -1, -1, 151, -1, -1, -1, { "Core(TM) i9-12###", 8 }, "Core i9 (Alder Lake-S)", "Intel 7" }, + { 6, 7, -1, -1, 151, -1, -1, -1, { "Core(TM) i7-12###", 8 }, "Core i7 (Alder Lake-S)", "Intel 7" }, + { 6, 7, -1, -1, 151, -1, -1, -1, { "Core(TM) i5-12###", 8 }, "Core i5 (Alder Lake-S)", "Intel 7" }, + { 6, 7, -1, -1, 151, -1, -1, -1, { "Core(TM) i3-12###", 8 }, "Core i3 (Alder Lake-S)", "Intel 7" }, + { 6, 7, -1, -1, 151, -1, -1, -1, { "Pentium(R) Gold G7###", 8 }, "Pentium Gold (Alder Lake-S)" , "Intel 7" }, + { 6, 7, -1, -1, 151, -1, -1, -1, { "Celeron(R) G6###", 6 }, "Celeron (Alder Lake-S)", "Intel 7" }, + { 6, 7, -1, -1, 151, -1, -1, -1, { "Core(TM) i9-12###HX", 12 }, "Core i9 (Alder Lake-HX)", "Intel 7" }, + { 6, 7, -1, -1, 151, -1, -1, -1, { "Core(TM) i7-12###HX", 12 }, "Core i7 (Alder Lake-HX)", "Intel 7" }, + { 6, 7, -1, -1, 151, -1, -1, -1, { "Core(TM) i5-12###HX", 12 }, "Core i5 (Alder Lake-HX)", "Intel 7" }, + { 6, 10, -1, -1, 154, -1, -1, -1, { "Core(TM) i7-12##P", 10 }, "Core i7 (Alder Lake-P)", "Intel 7" }, + { 6, 10, -1, -1, 154, -1, -1, -1, { "Core(TM) i5-12##P", 10 }, "Core i5 (Alder Lake-P)", "Intel 7" }, + { 6, 10, -1, -1, 154, -1, -1, -1, { "Core(TM) i3-12##P", 10 }, "Core i3 (Alder Lake-P)", "Intel 7" }, + { 6, 10, -1, -1, 154, -1, -1, -1, { "Core(TM) i7-12##U", 10 }, "Core i7 (Alder Lake-U)", "Intel 7" }, + { 6, 10, -1, -1, 154, -1, -1, -1, { "Core(TM) i5-12##U", 10 }, "Core i5 (Alder Lake-U)", "Intel 7" }, + { 6, 10, -1, -1, 154, -1, -1, -1, { "Core(TM) i3-12##U", 10 }, "Core i3 (Alder Lake-U)", "Intel 7" }, + { 6, 10, -1, -1, 154, -1, -1, -1, { "Pentium(R) Gold 8###", 6 }, "Pentium Gold (Alder Lake-U)", "Intel 7" }, + { 6, 10, -1, -1, 154, -1, -1, -1, { "Celeron(R) 7###", 4 }, "Celeron (Alder Lake-U)", "Intel 7" }, + { 6, 10, -1, -1, 154, -1, -1, -1, { "Core(TM) i9-12###H", 10 }, "Core i9 (Alder Lake-H)", "Intel 7" }, + { 6, 10, -1, -1, 154, -1, -1, -1, { "Core(TM) i7-12###H", 10 }, "Core i7 (Alder Lake-H)", "Intel 7" }, + { 6, 10, -1, -1, 154, -1, -1, -1, { "Core(TM) i5-12###H", 10 }, "Core i5 (Alder Lake-H)", "Intel 7" }, + { 6, 10, -1, -1, 154, -1, -1, -1, { "Core(TM) i7-12##UL", 12 }, "Core i7 (Alder Lake-PS)", "Intel 7" }, + { 6, 10, -1, -1, 154, -1, -1, -1, { "Core(TM) i5-12##UL", 12 }, "Core i5 (Alder Lake-PS)", "Intel 7" }, + { 6, 10, -1, -1, 154, -1, -1, -1, { "Core(TM) i3-12##UL", 12 }, "Core i3 (Alder Lake-PS)", "Intel 7" }, + { 6, 10, -1, -1, 154, -1, -1, -1, { "Celeron(R) 7###L", 6 }, "Celeron (Alder Lake-PS)", "Intel 7" }, + { 6, 10, -1, -1, 154, -1, -1, -1, { "Core(TM) i7-12###HL", 12 }, "Core i7 (Alder Lake-PS)", "Intel 7" }, + { 6, 10, -1, -1, 154, -1, -1, -1, { "Core(TM) i5-12###HL", 12 }, "Core i5 (Alder Lake-PS)", "Intel 7" }, + { 6, 10, -1, -1, 154, -1, -1, -1, { "Core(TM) i3-12###HL", 12 }, "Core i3 (Alder Lake-PS)", "Intel 7" }, + /* Sapphire Rapids CPUs (2023, 4th Xeon Scalable gen, Intel 7): https://en.wikichip.org/wiki/intel/microarchitectures/sapphire_rapids */ + { 6, 15, -1, -1, 143, -1, -1, -1, { "Xeon(R) w9-#4##", 6 }, "Xeon w9 (Sapphire Rapids-WS)", "Intel 7" }, + { 6, 15, -1, -1, 143, -1, -1, -1, { "Xeon(R) w7-#4##", 6 }, "Xeon w7 (Sapphire Rapids-WS)", "Intel 7" }, + { 6, 15, -1, -1, 143, -1, -1, -1, { "Xeon(R) w5-#4##", 6 }, "Xeon w5 (Sapphire Rapids-WS)", "Intel 7" }, + { 6, 15, -1, -1, 143, -1, -1, -1, { "Xeon(R) w3-#4##", 6 }, "Xeon w3 (Sapphire Rapids-WS)", "Intel 7" }, + { 6, 15, -1, -1, 143, -1, -1, -1, { "Xeon(R) Max #4##", 6 }, "Xeon Max (Sapphire Rapids-HBM)", "Intel 7" }, + { 6, 15, -1, -1, 143, -1, -1, -1, { "Xeon(R) Platinum #4##", 6 }, "Xeon Platinum (Sapphire Rapids-SP)", "Intel 7" }, + { 6, 15, -1, -1, 143, -1, -1, -1, { "Xeon(R) Gold #4##", 6 }, "Xeon Gold (Sapphire Rapids-SP)", "Intel 7" }, + { 6, 15, -1, -1, 143, -1, -1, -1, { "Xeon(R) Silver #4##", 6 }, "Xeon Silver (Sapphire Rapids-SP)" , "Intel 7" }, + { 6, 15, -1, -1, 143, -1, -1, -1, { "Xeon(R) Bronze #4##", 6 }, "Xeon Bronze (Sapphire Rapids-SP)" , "Intel 7" }, + + /* Gracemont CPUs (2021, Atom, Intel 7): https://en.wikipedia.org/wiki/Gracemont_(microarchitecture) */ + { 6, 14, -1, -1, 190, -1, -1, -1, { "Core(TM) i3-N3##", 10 }, "Core i3 (Alder Lake-N)", "Intel 7" }, /* Core i3 N300 + Core i3 N305 */ + { 6, 14, -1, -1, 190, 4, -1, -1, { "N##", 2 }, "Intel Processor (Alder Lake-N)", "Intel 7" }, + { 6, 14, -1, -1, 190, 2, -1, -1, { "N##", 2 }, "Intel Processor (Alder Lake-N)", "Intel 7" }, /* Intel Processor N50 */ + { 6, 14, -1, -1, 190, -1, -1, -1, { "Atom(TM) x7###E", 8 }, "Atom (Alder Lake-N)", "Intel 7" }, + /* Twin Lake CPUs (2025, Atom, Intel 7): https://en.wikichip.org/wiki/intel/microarchitectures/twin_lake */ + { 6, 14, -1, -1, 190, 8, -1, -1, { "Core(TM) 3 N#5#", 8 }, "Core 3 (Twin Lake-N)", "Intel 7" }, /* Core 3 N350 + Core 3 N355 */ + { 6, 14, -1, -1, 190, 4, -1, -1, { "N#5#", 4 }, "Intel Processor (Twin Lake-N)", "Intel 7" }, /* Intel Processor N150 + Intel Processor N150 */ + + /* Raptor Cove (P-cores) / Gracemont (E-cores) CPUs (2022, 13th Core i gen, Intel 7): https://en.wikipedia.org/wiki/Golden_Cove#Raptor_Cove */ + { 6, 15, -1, -1, 191, -1, -1, -1, { "Core(TM) i5-13###", 8 }, "Core i5 (Raptor Lake-S)", "Intel 7" }, /* "Golden Cove" cores */ + { 6, 15, -1, -1, 191, -1, -1, -1, { "Core(TM) i3-13###", 8 }, "Core i3 (Raptor Lake-S)", "Intel 7" }, /* "Golden Cove" cores */ + { 6, 7, -1, -1, 183, -1, -1, -1, { "Core(TM) i9-13###", 8 }, "Core i9 (Raptor Lake-S)", "Intel 7" }, + { 6, 7, -1, -1, 183, -1, -1, -1, { "Core(TM) i7-13###", 8 }, "Core i7 (Raptor Lake-S)", "Intel 7" }, + { 6, 7, -1, -1, 183, -1, -1, -1, { "Core(TM) i5-13###", 8 }, "Core i5 (Raptor Lake-S)", "Intel 7" }, + { 6, 7, -1, -1, 183, -1, -1, -1, { "Core(TM) i3-13###", 8 }, "Core i3 (Raptor Lake-S)", "Intel 7" }, + { 6, 7, -1, -1, 183, -1, -1, -1, { "Core(TM) i9-13###HX", 12 }, "Core i9 (Raptor Lake-HX)", "Intel 7" }, + { 6, 7, -1, -1, 183, -1, -1, -1, { "Core(TM) i7-13###HX", 12 }, "Core i7 (Raptor Lake-HX)", "Intel 7" }, + { 6, 7, -1, -1, 183, -1, -1, -1, { "Core(TM) i5-13###HX", 12 }, "Core i5 (Raptor Lake-HX)", "Intel 7" }, + { 6, 10, 2, -1, 186, -1, -1, -1, { "Core(TM) i7-13###P", 10 }, "Core i7 (Raptor Lake-P)", "Intel 7" }, + { 6, 10, 2, -1, 186, -1, -1, -1, { "Core(TM) i5-13###P", 10 }, "Core i5 (Raptor Lake-P)", "Intel 7" }, + { 6, 10, 3, -1, 186, -1, -1, -1, { "Core(TM) i7-13###U", 10 }, "Core i7 (Raptor Lake-U)", "Intel 7" }, + { 6, 10, 3, -1, 186, -1, -1, -1, { "Core(TM) i5-13###U", 10 }, "Core i5 (Raptor Lake-U)", "Intel 7" }, + { 6, 10, 3, -1, 186, -1, -1, -1, { "Core(TM) i3-13###U", 10 }, "Core i3 (Raptor Lake-U)", "Intel 7" }, + { 6, 10, 3, -1, 186, -1, -1, -1, { "U300", 4 }, "Intel Processor (Raptor Lake-U)", "Intel 7" }, /* Intel Processor U300 */ + { 6, 10, -1, -1, 186, -1, -1, -1, { "Core(TM) i9-13###H", 10 }, "Core i9 (Raptor Lake-H)", "Intel 7" }, + { 6, 10, -1, -1, 186, -1, -1, -1, { "Core(TM) i7-13###H", 10 }, "Core i7 (Raptor Lake-H)", "Intel 7" }, + { 6, 10, -1, -1, 186, -1, -1, -1, { "Core(TM) i5-13###H", 10 }, "Core i5 (Raptor Lake-H)", "Intel 7" }, + /* Emerald Rapids CPUs (2023, 5th Xeon Scalable gen, Intel 7): https://en.wikichip.org/wiki/intel/microarchitectures/emerald_rapids */ + { 6, 15, -1, -1, 207, -1, -1, -1, { "Xeon(R) Platinum #5##", 6 }, "Xeon Platinum (Emerald Rapids-SP)", "Intel 7" }, /* Xeon Platinum (8500) */ + { 6, 15, -1, -1, 207, -1, -1, -1, { "Xeon(R) Gold #5##", 6 }, "Xeon Gold (Emerald Rapids-SP)", "Intel 7" }, /* Xeon Gold (5500 and 6500) */ + { 6, 15, -1, -1, 207, -1, -1, -1, { "Xeon(R) Silver #5##", 6 }, "Xeon Silver (Emerald Rapids-SP)", "Intel 7" }, /* Xeon Silver (4500) */ + { 6, 15, -1, -1, 207, -1, -1, -1, { "Xeon(R) Bronze #5##", 6 }, "Xeon Bronze (Emerald Rapids-SP)", "Intel 7" }, /* Xeon Bronze (3500) */ + /* Raptor Lake Refresh CPUs (2023, 14th Core i gen, Intel 7): https://en.wikipedia.org/wiki/Raptor_Lake#List_of_14th_generation_Raptor_Lake_processors */ + { 6, 7, -1, -1, 183, -1, -1, -1, { "Core(TM) i9-14###", 8 }, "Core i9 (Raptor Lake-S)" , "Intel 7" }, + { 6, 7, -1, -1, 183, -1, -1, -1, { "Core(TM) i7-14###", 8 }, "Core i7 (Raptor Lake-S)" , "Intel 7" }, + { 6, 7, -1, -1, 183, -1, -1, -1, { "Core(TM) i5-14###", 8 }, "Core i5 (Raptor Lake-S)" , "Intel 7" }, + { 6, 7, -1, -1, 183, -1, -1, -1, { "Core(TM) i3-14###", 8 }, "Core i3 (Raptor Lake-S)" , "Intel 7" }, + { 6, 7, -1, -1, 183, 2, -1, -1, { "300", 2 }, "Intel Processor (Raptor Lake-S)", "Intel 7" }, /* Intel Processor 300 + Intel Processor 300T */ + { 6, 7, -1, -1, 183, -1, -1, -1, { "Core(TM) i9-14###HX", 12 }, "Core i9 (Raptor Lake-HX)", "Intel 7" }, + { 6, 7, -1, -1, 183, -1, -1, -1, { "Core(TM) i7-14###HX", 12 }, "Core i7 (Raptor Lake-HX)", "Intel 7" }, + { 6, 7, -1, -1, 183, -1, -1, -1, { "Core(TM) i5-14###HX", 12 }, "Core i5 (Raptor Lake-HX)", "Intel 7" }, + { 6, 7, -1, -1, 183, -1, -1, -1, { "Xeon(R) E-24##", 6 }, "Xeon E (Raptor Lake)", "Intel 7" }, + { 6, 7, -1, -1, 183, -1, -1, -1, { "Core(TM) 7 1##U", 8 }, "Core 7 (Raptor Lake-U)", "Intel 7" }, /* Core 7 150U */ + { 6, 7, -1, -1, 183, -1, -1, -1, { "Core(TM) 5 1##U", 8 }, "Core 5 (Raptor Lake-U)", "Intel 7" }, /* Core 5 120U */ + { 6, 7, -1, -1, 183, -1, -1, -1, { "Core(TM) 3 1##U", 8 }, "Core 3 (Raptor Lake-U)", "Intel 7" }, /* Core 3 100U */ + /* Raptor Lake Re-refresh CPUs (2025, Core Series 2, Intel 7): https://en.wikipedia.org/wiki/Raptor_Lake#List_of_Core_Series_2_processors */ + { 6, 7, -1, -1, 183, -1, -1, -1, { "Core(TM) 7 2##U", 8 }, "Core 7 (Raptor Lake-U)", "Intel 7" }, /* Core 7 250U */ + { 6, 7, -1, -1, 183, -1, -1, -1, { "Core(TM) 5 2##U", 8 }, "Core 5 (Raptor Lake-U)", "Intel 7" }, /* Core 5 220U */ + { 6, 7, -1, -1, 183, -1, -1, -1, { "Core(TM) 9 2##H", 8 }, "Core 9 (Raptor Lake-H)", "Intel 7" }, /* Core 9 270H */ + { 6, 7, -1, -1, 183, -1, -1, -1, { "Core(TM) 7 2##H", 8 }, "Core 7 (Raptor Lake-H)", "Intel 7" }, /* Core 7 240H + Core 7 250H */ + { 6, 7, -1, -1, 183, -1, -1, -1, { "Core(TM) 5 2##H", 8 }, "Core 5 (Raptor Lake-H)", "Intel 7" }, /* Core 5 210H + Core 5 220H */ + + /* Redwood Cove (P-cores) / Crestmont (E-cores) CPUs (2023, Core Ultra Series 1, Intel 4): https://en.wikipedia.org/wiki/Meteor_Lake */ + { 6, 10, -1, -1, 170, -1, -1, -1, { "Core(TM) Ultra 9 1##H", 10 }, "Core Ultra 9 (Meteor Lake-H)", "Intel 4" }, + { 6, 10, -1, -1, 170, -1, -1, -1, { "Core(TM) Ultra 7 1##H", 10 }, "Core Ultra 7 (Meteor Lake-H)", "Intel 4" }, + { 6, 10, -1, -1, 170, -1, -1, -1, { "Core(TM) Ultra 5 1##H", 10 }, "Core Ultra 5 (Meteor Lake-H)", "Intel 4" }, + { 6, 10, -1, -1, 170, -1, -1, -1, { "Core(TM) Ultra 7 1##U", 10 }, "Core Ultra 7 (Meteor Lake-U)", "Intel 4" }, + { 6, 10, -1, -1, 170, -1, -1, -1, { "Core(TM) Ultra 5 1##U", 10 }, "Core Ultra 5 (Meteor Lake-U)", "Intel 4" }, + /* Granite Rapids CPUs (2024, 6th Xeon Scalable gen, Intel 7): https://en.wikipedia.org/wiki/Granite_Rapids */ + { 6, 13, -1, -1, 173, -1, -1, -1, { "Xeon(R) 6[57]##P", 6 }, "Xeon 6 (Granite Rapids-SP)", "Intel 3" }, + //{ 6, ??, -1, -1, ???, -1, -1, -1, { "Xeon(R) 6[57]##P", 6 }, "Xeon 6 (Granite Rapids-AP)", "Intel 3" }, + //{ 6, 14, -1, -1, 174, -1, -1, -1, { "Xeon(R) ????", 4 }, "Xeon ??? (Granite Rapids-D)", "Intel 3" }, + + /* Lion Cove (P-cores) / Skymont (E-cores) CPUs (2024, Core Ultra Series 2, TSMC N3B): https://en.wikipedia.org/wiki/Arrow_Lake_(microprocessor) */ + { 6, 6, -1, -1, 198, -1, -1, -1, { "Core(TM) Ultra 9 2##", 8 }, "Core Ultra 9 (Arrow Lake-S)", "TSMC N3B" }, + { 6, 6, -1, -1, 198, -1, -1, -1, { "Core(TM) Ultra 7 2##", 8 }, "Core Ultra 7 (Arrow Lake-S)", "TSMC N3B" }, + { 6, 6, -1, -1, 198, -1, -1, -1, { "Core(TM) Ultra 5 2##", 8 }, "Core Ultra 5 (Arrow Lake-S)", "TSMC N3B" }, + { 6, 6, -1, -1, 181, -1, -1, -1, { "Core(TM) Ultra 7 2##U", 10 }, "Core Ultra 7 (Arrow Lake-U)", "TSMC N3B" }, /* Core Ultra 7 255U + Core Ultra 7 265U */ + { 6, 6, -1, -1, 181, -1, -1, -1, { "Core(TM) Ultra 5 2##U", 10 }, "Core Ultra 5 (Arrow Lake-U)", "TSMC N3B" }, /* Core Ultra 5 225U + Core Ultra 5 235U */ + { 6, 6, -1, -1, 197, -1, -1, -1, { "Core(TM) Ultra 9 2##H", 10 }, "Core Ultra 9 (Arrow Lake-H)", "TSMC N3B" }, /* Core Ultra 9 285H */ + { 6, 6, -1, -1, 197, -1, -1, -1, { "Core(TM) Ultra 7 2##H", 10 }, "Core Ultra 7 (Arrow Lake-H)", "TSMC N3B" }, /* Core Ultra 7 255H + Core Ultra 7 265H */ + { 6, 6, -1, -1, 197, -1, -1, -1, { "Core(TM) Ultra 5 2##H", 10 }, "Core Ultra 5 (Arrow Lake-H)", "TSMC N3B" }, /* Core Ultra 5 225H + Core Ultra 5 235H */ + { 6, 6, -1, -1, 197, -1, -1, -1, { "Core(TM) Ultra 9 2##HX", 12 }, "Core Ultra 9 (Arrow Lake-HX)", "TSMC N3B" }, /* Core Ultra 9 275HX + Core Ultra 9 285HX */ + { 6, 6, -1, -1, 197, -1, -1, -1, { "Core(TM) Ultra 7 2##HX", 12 }, "Core Ultra 7 (Arrow Lake-HX)", "TSMC N3B" }, /* Core Ultra 7 255HX + Core Ultra 7 265HX */ + { 6, 6, -1, -1, 197, -1, -1, -1, { "Core(TM) Ultra 5 2##HX", 12 }, "Core Ultra 5 (Arrow Lake-HX)", "TSMC N3B" }, /* Core Ultra 5 235HX + Core Ultra 5 245HX */ + { 6, 13, -1, -1, 189, -1, -1, -1, { "Core(TM) Ultra 9 2##V", 10 }, "Core Ultra 9 (Lunar Lake-V)", "TSMC N3B" }, + { 6, 13, -1, -1, 189, -1, -1, -1, { "Core(TM) Ultra 7 2##V", 10 }, "Core Ultra 7 (Lunar Lake-V)", "TSMC N3B" }, + { 6, 13, -1, -1, 189, -1, -1, -1, { "Core(TM) Ultra 5 2##V", 10 }, "Core Ultra 5 (Lunar Lake-V)", "TSMC N3B" }, + + /* Cougar Cove (P-cores) / Darkmont (E-cores and LP E-cores) CPUs (2025, Core Ultra Series 3, Intel 18A): https://en.wikipedia.org/wiki/Panther_Lake_(microprocessor) */ + // TBA +// F M S EF EM #cores L2$ L3$ Pattern Codename Technology + + + /* Itaniums */ + { 7, -1, -1, -1, -1, 1, -1, -1, { "", 0 }, "Itanium", UNKN_STR }, + { 15, -1, -1, 16, -1, 1, -1, -1, { "", 0 }, "Itanium 2", UNKN_STR }, +}; + +// https://github.com/anrieff/libcpuid/blob/2e4456ae0165db3155da2e8fba92afd5c090ca1b/libcpuid/recog_amd.c +/* + * Copyright 2008 Veselin Georgiev, + * anrieffNOSPAM @ mgail_DOT.com (convert to gmail) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + /* + * Useful links: + * - List of AMD CPU microarchitectures: https://en.wikipedia.org/wiki/List_of_AMD_CPU_microarchitectures + * - List of AMD Athlon processors: https://en.wikipedia.org/wiki/List_of_AMD_Athlon_processors#Desktop_processors + * - List of AMD Duron processors: https://en.wikipedia.org/wiki/List_of_AMD_Duron_processors + * - List of AMD Sempron processors: https://en.wikipedia.org/wiki/List_of_AMD_Sempron_processors + * - List of AMD Turion processors: https://en.wikipedia.org/wiki/List_of_AMD_Turion_processors + * - List of AMD Opteron processors: https://en.wikipedia.org/wiki/List_of_AMD_Opteron_processors + * - List of AMD Phenom processors: https://en.wikipedia.org/wiki/List_of_AMD_Phenom_processors + * - List of AMD FX processors: https://en.wikipedia.org/wiki/List_of_AMD_FX_processors + * - List of AMD processors with 3D graphics: https://en.wikipedia.org/wiki/List_of_AMD_processors_with_3D_graphics + * - List of AMD Ryzen processors: https://en.wikipedia.org/wiki/List_of_AMD_Ryzen_processors + * - List of AMD Epyc processors: https://en.wikipedia.org/wiki/Epyc#List_of_Epyc_processors + * - Processor Specifications: https://www.amd.com/en/products/specifications/processors.html + */ +const struct match_entry_t cpudb_amd[] = { +// F M S EF EM #cores L2$ L3$ Pattern Codename Technology + { -1, -1, -1, -1, -1, 1, -1, -1, { "", 0 }, "Unknown AMD CPU", UNKN_STR }, + + /* 486 and the likes */ + { 4, -1, -1, -1, -1, 1, -1, -1, { "", 0 }, "Unknown 486", UNKN_STR }, + { 4, 3, -1, -1, -1, 1, -1, -1, { "", 0 }, "AMD 486DX2", UNKN_STR }, + { 4, 7, -1, -1, -1, 1, -1, -1, { "", 0 }, "AMD 486DX2WB", UNKN_STR }, + { 4, 8, -1, -1, -1, 1, -1, -1, { "", 0 }, "AMD 486DX4", UNKN_STR }, + { 4, 9, -1, -1, -1, 1, -1, -1, { "", 0 }, "AMD 486DX4WB", UNKN_STR }, + + /* Pentia clones */ + { 5, -1, -1, -1, -1, 1, -1, -1, { "", 0 }, "Unknown K5", UNKN_STR }, + { 5, 0, -1, -1, -1, 1, -1, -1, { "", 0 }, "K5 (SSA/5)", UNKN_STR }, + { 5, 1, -1, -1, -1, 1, -1, -1, { "K5(tm)", 2 }, "K5 (5k86)", "350 nm" }, + { 5, 2, -1, -1, -1, 1, -1, -1, { "K5(tm)", 2 }, "K5 (5k86)", "350 nm" }, + { 5, 3, -1, -1, -1, 1, -1, -1, { "K5(tm)", 2 }, "K5 (5k86)", "350 nm" }, + + /* K6 Architecture */ + { 5, -1, -1, -1, -1, 1, -1, -1, { "", 0 }, "Unknown K6", UNKN_STR }, + { 5, 6, -1, -1, -1, 1, -1, -1, { "K6", 2 }, "K6", "350 nm" }, + { 5, 7, -1, -1, -1, 1, -1, -1, { "K6", 2 }, "K6 (Little Foot)", "250 nm" }, + { 5, 8, 0, -1, -1, 1, -1, -1, { "K6(tm)", 2 }, "K6-2 (Chomper)", "250 nm" }, + { 5, 8, 12, -1, -1, 1, -1, -1, { "K6(tm)", 2 }, "K6-2 (Chomper Extended)", "250 nm" }, + { 5, 9, -1, -1, -1, 1, -1, -1, { "K6(tm)", 2 }, "K6-III (Sharptooth)", "250 nm" }, + { 5, 13, -1, -1, -1, 1, -1, -1, { "K6(tm)", 2 }, "K6-2+", "180 nm" }, + { 5, 13, -1, -1, -1, 1, -1, -1, { "K6(tm)-III ", 4 }, "K6-III+", "180 nm" }, + + /* K7 Architecture */ + { 6, -1, -1, 15, -1, 1, -1, -1, { "", 0 }, "Unknown K7", UNKN_STR }, + + { 6, 1, -1, -1, -1, 1, -1, -1, { "K7(tm)", 0 }, "Athlon (Argon)", "250 nm" }, + + { 6, 2, -1, -1, -1, 1, -1, -1, { "Athlon(tm)", 0 }, "Athlon (Pluto/Orion)", "180 nm" }, + + { 6, 3, -1, -1, -1, 1, -1, -1, { "Duron(tm)", 2 }, "Duron (Spitfire)", "180 nm" }, + { 6, 3, -1, -1, -1, 1, -1, -1, { "Duron(tm) M", 4 }, "Mobile Duron (Spitfire)", "180 nm" }, + + { 6, 4, -1, -1, -1, 1, -1, -1, { "Athlon(tm)", 2 }, "Athlon (ThunderBird)", "180 nm" }, + + { 6, 6, -1, -1, -1, 1, -1, -1, { "Athlon XP", 4 }, "Athlon (Palomino)", "180 nm" }, + { 6, 6, -1, -1, -1, 1, -1, -1, { "Athlon(tm) MP", 4 }, "Athlon MP (Palomino)", "180 nm" }, + { 6, 6, -1, -1, -1, 1, -1, -1, { "Duron(tm)", 2 }, "Duron (Palomino)", "180 nm" }, + + { 6, 7, -1, -1, -1, 1, -1, -1, { "Duron(tm)", 2 }, "Duron (Morgan)", "180 nm" }, + { 6, 7, -1, -1, -1, 1, -1, -1, { "Duron(tm) M", 4 }, "Mobile Duron (Camaro)", "180 nm" }, + + { 6, 8, -1, -1, -1, 1, -1, -1, { "Athlon", 2 }, "Athlon XP (Thoroughbred)", "130 nm" }, + { 6, 8, -1, -1, -1, 1, -1, -1, { "Athlon(tm) XP", 4 }, "Athlon XP (Thoroughbred)", "130 nm" }, + { 6, 8, -1, -1, -1, 1, -1, -1, { "Duron(tm)", 2 }, "Duron (Applebred)", "130 nm" }, + { 6, 8, -1, -1, -1, 1, -1, -1, { "Sempron(tm)", 2 }, "Sempron (Thoroughbred)", "130 nm" }, + { 6, 8, -1, -1, -1, 1, 128, -1, { "Sempron(tm)", 2 }, "Sempron (Thoroughbred)", "130 nm" }, + { 6, 8, -1, -1, -1, 1, 256, -1, { "Sempron(tm)", 2 }, "Sempron (Thoroughbred)", "130 nm" }, + { 6, 8, -1, -1, -1, 1, -1, -1, { "Athlon(tm) MP", 4 }, "Athlon MP (Thoroughbred)", "130 nm" }, + { 6, 8, -1, -1, -1, 1, -1, -1, { "Athlon(tm) XP-M", 6 }, "Mobile Athlon (Thoroughbred)", "130 nm" }, + + { 6, 10, -1, -1, -1, 1, 512, -1, { "Athlon(tm) XP", 4 }, "Athlon XP (Barton)", "130 nm" }, + { 6, 10, -1, -1, -1, 1, 512, -1, { "Sempron(tm)", 2 }, "Sempron (Barton)", "130 nm" }, + { 6, 10, -1, -1, -1, 1, 256, -1, { "Sempron(tm)", 2 }, "Sempron (Thorton)", "130 nm" }, + { 6, 10, -1, -1, -1, 1, 256, -1, { "Athlon(tm) XP", 4 }, "Athlon XP (Thorton)", "130 nm" }, + { 6, 10, -1, -1, -1, 1, -1, -1, { "Athlon(tm) MP", 4 }, "Athlon MP (Barton)", "130 nm" }, + { 6, 10, -1, -1, -1, 1, -1, -1, { "Athlon(tm) XP-M", 6 }, "Mobile Athlon (Barton)", "130 nm" }, + + /* K8 Architecture */ + { 15, -1, -1, 15, -1, 1, -1, -1, { "", 0 }, "Unknown K8", UNKN_STR }, + { 15, -1, -1, 16, -1, 1, -1, -1, { "", 0 }, "Unknown K9", UNKN_STR }, + { 15, -1, -1, 15, -1, 1, -1, -1, { "", 0 }, "Unknown A64", UNKN_STR }, + { 15, -1, -1, 15, -1, 1, -1, -1, { "Opteron(tm)", 2 }, "Opteron", UNKN_STR }, + { 15, -1, -1, 15, -1, 2, -1, -1, { "Dual Core AMD Opteron", 8 }, "Opteron (Dual Core)", UNKN_STR }, + { 15, 1, -1, 15, 65, 2, -1, -1, { "Opteron(tm) 22##", 6 }, "Opteron (Santa Rosa)", "90 nm" }, + { 15, 3, -1, 15, -1, 1, -1, -1, { "Opteron(tm)", 2 }, "Opteron", UNKN_STR }, + { 15, 3, -1, 15, -1, 2, -1, -1, { "Dual Core AMD Opteron", 8 }, "Opteron (Dual Core)", UNKN_STR }, + { 15, 5, -1, 15, 5, -1, -1, -1, { "Opteron(tm) [128]##", 4 }, "Opteron (SledgeHammer)", "130 nm" }, + { 15, -1, -1, 15, -1, 1, 512, -1, { "Athlon(tm) 64", 4 }, "Athlon 64 (512K)", UNKN_STR }, + { 15, -1, -1, 15, -1, 1, 1024, -1, { "Athlon(tm) 64", 4 }, "Athlon 64 (1024K)", UNKN_STR }, + { 15, -1, -1, 15, -1, 1, -1, -1, { "Athlon(tm) FX", 4 }, "Athlon FX", UNKN_STR }, + { 15, -1, -1, 15, -1, 1, -1, -1, { "Athlon(tm) 64 FX", 6 }, "Athlon 64 FX", UNKN_STR }, + { 15, 3, -1, 15, 35, 2, -1, -1, { "Athlon(tm) 64 FX", 6 }, "Athlon 64 FX X2 (Toledo)", "90 nm" }, + { 15, -1, -1, 15, -1, 2, 512, -1, { "Athlon(tm) 64 X2", 6 }, "Athlon 64 X2 (512K)", UNKN_STR }, + { 15, -1, -1, 15, -1, 2, 1024, -1, { "Athlon(tm) 64 X2", 6 }, "Athlon 64 X2 (1024K)", UNKN_STR }, + { 15, -1, -1, 15, -1, 1, 512, -1, { "Turion(tm) 64", 4 }, "Turion 64 (512K)", UNKN_STR }, + { 15, -1, -1, 15, -1, 1, 1024, -1, { "Turion(tm) 64", 4 }, "Turion 64 (1024K)", UNKN_STR }, + { 15, -1, -1, 15, -1, 2, 512, -1, { "Turion(tm) X2", 4 }, "Turion 64 X2 (512K)", UNKN_STR }, + { 15, -1, -1, 15, -1, 2, 1024, -1, { "Turion(tm) X2", 4 }, "Turion 64 X2 (1024K)", UNKN_STR }, + { 15, -1, -1, 15, -1, 1, 128, -1, { "Sempron(tm)", 2 }, "A64 Sempron (128K)", UNKN_STR }, + { 15, -1, -1, 15, -1, 1, 256, -1, { "Sempron(tm)", 2 }, "A64 Sempron (256K)", UNKN_STR }, + { 15, -1, -1, 15, -1, 1, 512, -1, { "Sempron(tm)", 2 }, "A64 Sempron (512K)", UNKN_STR }, + { 15, -1, -1, 15, 0x4f, 1, 512, -1, { "Athlon(tm) 64", 4 }, "Athlon 64 (Orleans/512K)", "90 nm" }, + { 15, -1, -1, 15, 0x5f, 1, 512, -1, { "Athlon(tm) 64", 4 }, "Athlon 64 (Orleans/512K)", "90 nm" }, + { 15, -1, -1, 15, 0x2f, 1, 512, -1, { "Athlon(tm) 64", 4 }, "Athlon 64 (Venice/512K)", "90 nm" }, + { 15, -1, -1, 15, 0x2c, 1, 512, -1, { "Athlon(tm) 64", 4 }, "Athlon 64 (Venice/512K)", "90 nm" }, + { 15, -1, -1, 15, 0x1f, 1, 512, -1, { "Athlon(tm) 64", 4 }, "Athlon 64 (Winchester/512K)", "90 nm" }, + { 15, -1, -1, 15, 0x0c, 1, 512, -1, { "Athlon(tm) 64", 4 }, "Athlon 64 (Newcastle/512K)", "130 nm" }, + { 15, -1, -1, 15, 0x27, 1, 512, -1, { "Athlon(tm) 64", 4 }, "Athlon 64 (San Diego/512K)", "90 nm" }, + { 15, -1, -1, 15, 0x37, 1, 512, -1, { "Athlon(tm) 64", 4 }, "Athlon 64 (San Diego/512K)", "90 nm" }, + { 15, -1, -1, 15, 0x04, 1, 512, -1, { "Athlon(tm) 64", 4 }, "Athlon 64 (ClawHammer/512K)", "130 nm" }, + + { 15, -1, -1, 15, 0x5f, 1, 1024, -1, { "Athlon(tm) 64", 4 }, "Athlon 64 (Orleans/1024K)", "90 nm" }, + { 15, -1, -1, 15, 0x27, 1, 1024, -1, { "Athlon(tm) 64", 4 }, "Athlon 64 (San Diego/1024K)", "90 nm" }, + { 15, -1, -1, 15, 0x04, 1, 1024, -1, { "Athlon(tm) 64", 4 }, "Athlon 64 (ClawHammer/1024K)", "130 nm" }, + + { 15, -1, -1, 15, 0x4b, 2, 256, -1, { "Athlon(tm) 64 X2", 6 }, "Athlon 64 X2 (Windsor/256K)", "90 nm" }, + + { 15, -1, -1, 15, 0x23, 2, 512, -1, { "Athlon(tm) 64 X2", 6 }, "Athlon 64 X2 (Toledo/512K)", "90 nm" }, + { 15, -1, -1, 15, 0x4b, 2, 512, -1, { "Athlon(tm) 64 X2", 6 }, "Athlon 64 X2 (Windsor/512K)", "90 nm" }, + { 15, -1, -1, 15, 0x43, 2, 512, -1, { "Athlon(tm) 64 X2", 6 }, "Athlon 64 X2 (Windsor/512K)", "90 nm" }, + { 15, -1, -1, 15, 0x6b, 2, 512, -1, { "Athlon(tm) 64 X2", 6 }, "Athlon 64 X2 (Brisbane/512K)", "65 nm" }, + { 15, -1, -1, 15, 0x2b, 2, 512, -1, { "Athlon(tm) 64 X2", 6 }, "Athlon 64 X2 (Manchester/512K)", "90 nm" }, + + { 15, -1, -1, 15, 0x23, 2, 1024, -1, { "Athlon(tm) 64 X2", 6 }, "Athlon 64 X2 (Toledo/1024K)", "90 nm" }, + { 15, -1, -1, 15, 0x43, 2, 1024, -1, { "Athlon(tm) 64 X2", 6 }, "Athlon 64 X2 (Windsor/1024K)", "90 nm" }, + + { 15, -1, -1, 15, 0x08, 1, 128, -1, { "Mobile AMD Sempron(tm)", 6 }, "Mobile Sempron 64 (Dublin/128K)", "130 nm" }, + { 15, -1, -1, 15, 0x08, 1, 256, -1, { "Mobile AMD Sempron(tm)", 6 }, "Mobile Sempron 64 (Dublin/256K)", "130 nm" }, + { 15, -1, -1, 15, 0x0c, 1, 256, -1, { "Sempron(tm)", 2 }, "Sempron 64 (Paris)", "130 nm" }, + { 15, -1, -1, 15, 0x1c, 1, 128, -1, { "Sempron(tm)", 2 }, "Sempron 64 (Palermo/128K)", "90 nm" }, + { 15, -1, -1, 15, 0x1c, 1, 256, -1, { "Sempron(tm)", 2 }, "Sempron 64 (Palermo/256K)", "90 nm" }, + { 15, -1, -1, 15, 0x1c, 1, 128, -1, { "Mobile AMD Sempron(tm)", 6 }, "Mobile Sempron 64 (Sonora/128K)", "90 nm" }, + { 15, -1, -1, 15, 0x1c, 1, 256, -1, { "Mobile AMD Sempron(tm)", 6 }, "Mobile Sempron 64 (Sonora/256K)", "90 nm" }, + { 15, -1, -1, 15, 0x2c, 1, 128, -1, { "Sempron(tm)", 2 }, "Sempron 64 (Palermo/128K)", "90 nm" }, + { 15, -1, -1, 15, 0x2c, 1, 256, -1, { "Sempron(tm)", 2 }, "Sempron 64 (Palermo/256K)", "90 nm" }, + { 15, -1, -1, 15, 0x2c, 1, 128, -1, { "Mobile AMD Sempron(tm)", 6 }, "Mobile Sempron 64 (Albany/128K)", "90 nm" }, + { 15, -1, -1, 15, 0x2c, 1, 256, -1, { "Mobile AMD Sempron(tm)", 6 }, "Mobile Sempron 64 (Albany/256K)", "90 nm" }, + { 15, -1, -1, 15, 0x2f, 1, 128, -1, { "Sempron(tm)", 2 }, "Sempron 64 (Palermo/128K)", "90 nm" }, + { 15, -1, -1, 15, 0x2f, 1, 256, -1, { "Sempron(tm)", 2 }, "Sempron 64 (Palermo/256K)", "90 nm" }, + { 15, -1, -1, 15, 0x4f, 1, 128, -1, { "Sempron(tm)", 2 }, "Sempron 64 (Manila/128K)", "90 nm" }, + { 15, -1, -1, 15, 0x4f, 1, 256, -1, { "Sempron(tm)", 2 }, "Sempron 64 (Manila/256K)", "90 nm" }, + { 15, -1, -1, 15, 0x5f, 1, 128, -1, { "Sempron(tm)", 2 }, "Sempron 64 (Manila/128K)", "90 nm" }, + { 15, -1, -1, 15, 0x5f, 1, 256, -1, { "Sempron(tm)", 2 }, "Sempron 64 (Manila/256K)", "90 nm" }, + { 15, -1, -1, 15, 0x6b, 2, 256, -1, { "Sempron(tm)", 2 }, "Sempron 64 Dual (Sherman/256K)", "65 nm" }, + { 15, -1, -1, 15, 0x6b, 2, 512, -1, { "Sempron(tm)", 2 }, "Sempron 64 Dual (Sherman/512K)", "65 nm" }, + { 15, -1, -1, 15, 0x7c, 1, 512, -1, { "Athlon(tm) 64", 4 }, "Athlon 64 (Sherman/512K)", "65 nm" }, + { 15, -1, -1, 15, 0x7f, 1, 256, -1, { "Sempron(tm)", 2 }, "Sempron 64 (Sparta/256K)", "65 nm" }, + { 15, -1, -1, 15, 0x7f, 1, 512, -1, { "Sempron(tm)", 2 }, "Sempron 64 (Sparta/512K)", "65 nm" }, + { 15, -1, -1, 15, 0x4c, 1, 256, -1, { "Mobile AMD Sempron(tm)", 6 }, "Mobile Sempron 64 (Keene/256K)", "90 nm" }, + { 15, -1, -1, 15, 0x4c, 1, 512, -1, { "Mobile AMD Sempron(tm)", 6 }, "Mobile Sempron 64 (Keene/512K)", "90 nm" }, + + { 15, -1, -1, 15, 0x24, 1, 512, -1, { "Turion(tm) 64", 4 }, "Turion 64 (Lancaster/512K)", "90 nm" }, + { 15, -1, -1, 15, 0x24, 1, 1024, -1, { "Turion(tm) 64", 4 }, "Turion 64 (Lancaster/1024K)", "90 nm" }, + { 15, -1, -1, 15, 0x48, 2, 256, -1, { "Turion(tm) X2", 4 }, "Turion X2 (Taylor)", "90 nm" }, + { 15, -1, -1, 15, 0x48, 2, 512, -1, { "Turion(tm) X2", 4 }, "Turion X2 (Trinidad)", "90 nm" }, + { 15, -1, -1, 15, 0x4c, 1, 512, -1, { "Turion(tm) 64", 4 }, "Turion 64 (Richmond)", "90 nm" }, + { 15, -1, -1, 15, 0x68, 2, 256, -1, { "Turion(tm) X2", 4 }, "Turion X2 (Tyler/256K)", "65 nm" }, + { 15, -1, -1, 15, 0x68, 2, 512, -1, { "Turion(tm) X2", 4 }, "Turion X2 (Tyler/512K)", "65 nm" }, + { 15, -1, -1, 17, 3, 2, 512, -1, { "Turion(tm) X2", 4 }, "Turion X2 (Griffin/512K)", "65 nm" }, + { 15, -1, -1, 17, 3, 2, 1024, -1, { "Turion(tm) X2", 4 }, "Turion X2 (Griffin/1024K)", "65 nm" }, + + /* K10 Architecture (2007) */ + { 15, 2, -1, 16, -1, 3, -1, -1, { "Phenom(tm)", 2 }, "Phenom X3 (Toliman)", "65 nm" }, + { 15, 2, -1, 16, -1, 4, -1, -1, { "Phenom(tm)", 2 }, "Phenom X4 (Agena)", "65 nm" }, + { 15, 2, -1, 16, -1, 3, 512, -1, { "Phenom(tm)", 2 }, "Phenom X3 (Toliman/256K)", "65 nm" }, + { 15, 2, -1, 16, -1, 3, 512, -1, { "Phenom(tm)", 2 }, "Phenom X3 (Toliman/512K)", "65 nm" }, + { 15, 2, -1, 16, -1, 4, 128, -1, { "Phenom(tm)", 2 }, "Phenom X4 (Agena/128K)", "65 nm" }, + { 15, 2, -1, 16, -1, 4, 256, -1, { "Phenom(tm)", 2 }, "Phenom X4 (Agena/256K)", "65 nm" }, + { 15, 2, -1, 16, -1, 4, 512, -1, { "Phenom(tm)", 2 }, "Phenom X4 (Agena/512K)", "65 nm" }, + { 15, 2, -1, 16, -1, 2, 512, -1, { "Athlon(tm) 64 X2", 6 }, "Athlon X2 (Kuma)", "65 nm" }, + /* Phenom II derivates: */ + { 15, 4, -1, 16, -1, 1, 1024, -1, { "Sempron(tm)", 2 }, "Sempron (Sargas)", "45 nm" }, + { 15, 4, -1, 16, -1, 2, 512, -1, { "Phenom(tm) II", 4 }, "Phenom II X2 (Callisto)", "45 nm" }, + { 15, 4, -1, 16, -1, 3, 512, -1, { "Phenom(tm) II", 4 }, "Phenom II X3 (Heka)", "45 nm" }, + { 15, 4, -1, 16, 4, 4, 512, -1, { "Phenom(tm) II", 4 }, "Phenom II X4 (Deneb)", "45 nm" }, + { 15, 5, -1, 16, 5, 4, 512, -1, { "Phenom(tm) II", 4 }, "Phenom II X4 (Deneb)", "45 nm" }, + { 15, 4, -1, 16, 10, 4, 512, -1, { "Phenom(tm) II", 4 }, "Phenom II X4 (Zosma)", "45 nm" }, + { 15, 4, -1, 16, 10, 6, 512, -1, { "Phenom(tm) II", 4 }, "Phenom II X6 (Thuban)", "45 nm" }, + /* Athlon II derivates: */ + { 15, 6, -1, 16, 6, 2, 512, -1, { "Athlon(tm) II", 4 }, "Athlon II (Champlain)", "45 nm" }, + { 15, 6, -1, 16, 6, 2, 512, -1, { "Athlon(tm) II X2", 6 }, "Athlon II X2 (Regor)", "45 nm" }, + { 15, 6, -1, 16, 6, 2, 1024, -1, { "Athlon(tm) II X2", 6 }, "Athlon II X2 (Regor)", "45 nm" }, + { 15, 5, -1, 16, 5, 3, 512, -1, { "Athlon(tm) II X3", 6 }, "Athlon II X3 (Rana)", "45 nm" }, + { 15, 5, -1, 16, 5, 4, 512, -1, { "Athlon(tm) X4", 4 }, "Athlon II X4 (Propus)", "45 nm" }, + { 15, 5, -1, 16, 5, 4, 512, -1, { "Athlon(tm) II X4", 6 }, "Athlon II X4 (Propus)", "45 nm" }, + /* Opteron derivates: */ + { 15, 2, -1, 16, 2, -1, -1, -1, { "Opteron(tm) [28]3##", 4 }, "Opteron (Barcelona)", "45 nm" }, + { 15, 4, -1, 16, 4, -1, -1, -1, { "Opteron(tm) [28]3##", 4 }, "Opteron (Shanghai)", "45 nm" }, + { 15, 8, -1, 16, 8, -1, -1, -1, { "Opteron(tm) [28]4##", 4 }, "Opteron (Istanbul)", "45 nm" }, + { 15, 8, -1, 16, 8, -1, -1, -1, { "Opteron(tm) 41##", 4 }, "Opteron (Lisbon)", "45 nm" }, + { 15, 9, -1, 16, 9, 8, -1, -1, { "Opteron(tm) 64##", 4 }, "Opteron (Magny-Cours)", "45 nm" }, + + /* Llano APUs (2011): */ + { 15, 1, -1, 18, 1, 4, -1, -1, { "Athlon(tm) II X4 6##", 6 }, "Athlon II X4 (Llano)", "GF 32SHP" }, + { 15, 1, -1, 18, 1, 2, -1, -1, { "Athlon(tm) II X2 2##", 6 }, "Athlon II X2 (Llano)", "GF 32SHP" }, + { 15, 1, -1, 18, 1, 2, -1, -1, { "Sempron(tm) X2 1##", 6 }, "Sempron X2 (Llano)", "GF 32SHP" }, + { 15, 1, -1, 18, 1, -1, -1, -1, { "E2-3###", 4 }, "E-Series (Llano)", "GF 32SHP" }, + { 15, 1, -1, 18, 1, -1, -1, -1, { "A[468]-3###", 4 }, "A-Series (Llano)", "GF 32SHP" }, + + /* Family 14h: Bobcat Architecture (2011) */ + { 15, 1, -1, 20, -1, -1, -1, -1, { "C-[356]#", 4 }, "C-Series (Ontario)", "TSMC N40" }, + { 15, 1, -1, 20, -1, -1, -1, -1, { "E-[234]##", 4 }, "E-Series (Zacate)", "TSMC N40" }, + { 15, 1, -1, 20, -1, -1, -1, -1, { "G-T##[LRNE]", 6 }, "G-Series (Zacate)", "TSMC N40" }, + { 15, 1, -1, 20, -1, -1, -1, -1, { "Z-##", 4 }, "Z-Series (Desna)", "TSMC N40" }, + + /* Family 15h: Bulldozer Architecture (2011) */ + { 15, -1, -1, 21, 0, -1, -1, -1, { "FX(tm)-[468]###", 4 }, "FX (Zambezi)", "GF 32SHP" }, + { 15, -1, -1, 21, 1, -1, -1, -1, { "FX(tm)-[468]###", 4 }, "FX (Zambezi)", "GF 32SHP" }, + { 15, -1, -1, 21, 1, -1, -1, -1, { "Opteron(tm)", 2 }, "Opteron (Interlagos)", "GF 32SHP" }, + /* 2nd-gen, Piledriver core (2012): */ + { 15, -1, -1, 21, 2, -1, -1, -1, { "FX(tm)-[4689]###", 4 }, "FX (Vishera)", "GF 32SHP" }, + { 15, 0, -1, 21, 16, 4, -1, -1, { "Athlon(tm) X4 7##", 6 }, "Athlon X4 (Trinity)", "GF 32SHP" }, + { 15, 0, -1, 21, 16, 2, -1, -1, { "Athlon(tm) X2 3##", 6 }, "Athlon X2 (Trinity)", "GF 32SHP" }, + { 15, 0, -1, 21, 16, 2, -1, -1, { "Sempron(tm) X2 2##", 6 }, "Sempron X2 (Trinity)", "GF 32SHP" }, + { 15, 0, -1, 21, 16, -1, -1, -1, { "A[468]-5###", 4 }, "A-Series (Trinity)", "GF 32SHP" }, + { 15, 0, -1, 21, 16, -1, -1, -1, { "A10-5###", 4 }, "A-Series (Trinity)", "GF 32SHP" }, + { 15, 0, -1, 21, 16, -1, -1, -1, { "A[468]-4###M", 6 }, "A-Series (Trinity)", "GF 32SHP" }, + { 15, 0, -1, 21, 16, -1, -1, -1, { "A10-4###M", 6 }, "A-Series (Trinity)", "GF 32SHP" }, + { 15, 0, -1, 21, 19, -1, -1, -1, { "FX(tm)-6##K", 6 }, "FX (Richland)", "GF 32SHP" }, + { 15, 0, -1, 21, 19, 4, -1, -1, { "Athlon(tm) X4 7##", 6 }, "Athlon X4 (Richland)", "GF 32SHP" }, + { 15, 0, -1, 21, 19, 2, -1, -1, { "Athlon(tm) X2 3##", 6 }, "Athlon X2 (Richland)", "GF 32SHP" }, + { 15, 0, -1, 21, 19, 2, -1, -1, { "Sempron(tm) X2 2##", 6 }, "Sempron X2 (Richland)", "GF 32SHP" }, + { 15, 0, -1, 21, 19, -1, -1, -1, { "A4 PRO-7###B", 8 }, "A-Series (Richland)", "GF 32SHP" }, + { 15, 0, -1, 21, 19, -1, -1, -1, { "A[468]-[467]###", 4 }, "A-Series (Richland)", "GF 32SHP" }, + { 15, 0, -1, 21, 19, -1, -1, -1, { "A10-6###", 4 }, "A-Series (Richland)", "GF 32SHP" }, + { 15, 0, -1, 21, 19, -1, -1, -1, { "A[468]-5###M", 6 }, "A-Series (Richland)", "GF 32SHP" }, + { 15, 0, -1, 21, 19, -1, -1, -1, { "A10-5###M", 6 }, "A-Series (Richland)", "GF 32SHP" }, + { 15, 2, -1, 21, 2, -1, -1, -1, { "Opteron(tm)", 2 }, "Opteron (Abu Dhabi)", "GF 32SHP" }, + /* 3rd-gen, Steamroller core (2014): */ + { 15, 8, -1, 21, 48, -1, -1, -1, { "FX(tm)-7##K", 6 }, "FX (Kaveri)", "TSMC N28" }, + { 15, 8, -1, 21, 48, -1, -1, -1, { "FX(tm)-7###", 4 }, "FX (Kaveri)", "TSMC N28" }, + { 15, 8, -1, 21, 48, 4, -1, -1, { "Athlon(tm) X4 8##", 6 }, "Athlon X4 (Kaveri)", "TSMC N28" }, + { 15, 8, -1, 21, 48, 2, -1, -1, { "Athlon(tm) X2 4##", 6 }, "Athlon X2 (Kaveri)", "TSMC N28" }, + { 15, 8, -1, 21, 48, -1, -1, -1, { "A[468] PRO-[78]###B", 8 }, "A-Series (Kaveri)", "TSMC N28" }, + { 15, 8, -1, 21, 48, -1, -1, -1, { "A[468]-7###", 4 }, "A-Series (Kaveri)", "TSMC N28" }, + { 15, 8, -1, 21, 48, -1, -1, -1, { "A10 PRO-[78]###B", 8 }, "A-Series (Kaveri)", "TSMC N28" }, + { 15, 8, -1, 21, 48, -1, -1, -1, { "A10-7###", 4 }, "A-Series (Kaveri)", "TSMC N28" }, + { 15, 8, -1, 21, 56, -1, -1, -1, { "A[468]-[78]###", 4 }, "A-Series (Godavari)", "TSMC N28" }, + { 15, 8, -1, 21, 56, -1, -1, -1, { "A10-[78]###", 4 }, "A-Series (Godavari)", "TSMC N28" }, + { 15, 8, -1, 21, 56, 4, -1, -1, { "Athlon(tm) X4 8##", 6 }, "Athlon X4 (Godavari)", "TSMC N28" }, + { 15, 0, -1, 21, 48, -1, -1, -1, { "RX-###", 4 }, "R-Series (Bald Eagle)", "TSMC N28" }, + /* 4th-gen, Excavator core (2015): */ + { 15, 0, -1, 21, 96, -1, -1, -1, { "FX-8###P", 6 }, "FX (Carrizo)", "GF 28SHP" }, + { 15, 0, -1, 21, 96, 4, -1, -1, { "Athlon(tm) X4 8##", 6 }, "Athlon X4 (Carrizo)", "GF 28SHP" }, + { 15, 0, -1, 21, 96, -1, -1, -1, { "A[68] PRO-8###", 6 }, "A-Series (Carrizo)", "GF 28SHP" }, + { 15, 0, -1, 21, 96, -1, -1, -1, { "A[68]-[78]###", 4 }, "A-Series (Carrizo)", "GF 28SHP" }, + { 15, 0, -1, 21, 96, -1, -1, -1, { "A1[02] PRO-8###", 6 }, "A-Series (Carrizo)", "GF 28SHP" }, + { 15, 0, -1, 21, 96, -1, -1, -1, { "A1[02]-8###", 4 }, "A-Series (Carrizo)", "GF 28SHP" }, + { 15, 5, -1, 21, 101, -1, -1, -1, { "FX-9###P", 6 }, "FX (Bristol Ridge)", "GF 28SHP" }, + { 15, 5, -1, 21, 101, -1, -1, -1, { "Athlon(tm) X4 9##", 6 }, "Athlon X4 (Bristol Ridge)", "GF 28SHP" }, + { 15, 5, -1, 21, 101, -1, -1, -1, { "A[68] PRO-9###", 6 }, "A-Series (Bristol Ridge)", "GF 28SHP" }, + { 15, 5, -1, 21, 101, -1, -1, -1, { "A[68]-9###", 4 }, "A-Series (Bristol Ridge)", "GF 28SHP" }, + { 15, 5, -1, 21, 101, -1, -1, -1, { "A1[02] PRO-9###", 6 }, "A-Series (Bristol Ridge)", "GF 28SHP" }, + { 15, 5, -1, 21, 101, -1, -1, -1, { "A1[02]-9###", 4 }, "A-Series (Bristol Ridge)", "GF 28SHP" }, + { 15, 0, -1, 21, 112, 2, -1, -1, { "A[469]-9###", 4 }, "A-Series (Stoney Ridge)", "GF 28SHP" }, + { 15, 0, -1, 21, 112, -1, -1, -1, { "E2-9###", 4 }, "E-Series (Stoney Ridge)", "GF 28SHP" }, + { 15, 0, -1, 21, 96, -1, -1, -1, { "Opteron(tm) X3###", 6 }, "Opteron (Toronto)", "GF 28SHP" }, + + /* Family 16h: Jaguar Architecture (2013) */ + { 15, 0, -1, 22, 0, 4, -1, -1, { "Athlon(tm) X4 5##", 6 }, "Athlon X4 (Kabini)", "TSMC N28" }, + { 15, 0, -1, 22, 0, 4, -1, -1, { "Athlon(tm) 5###", 4 }, "Athlon X4 (Kabini)", "TSMC N28" }, + { 15, 0, -1, 22, 0, -1, -1, -1, { "Sempron(tm) [23]###", 4 }, "Sempron (Kabini)", "TSMC N28" }, + { 15, 0, -1, 22, 0, -1, -1, -1, { "E1-2###", 4 }, "E-Series (Kabini)", "TSMC N28" }, + { 15, 0, -1, 22, 0, -1, -1, -1, { "E2-3###", 4 }, "E-Series (Kabini)", "TSMC N28" }, + { 15, 0, -1, 22, 0, -1, -1, -1, { "A4 PRO-3###", 6 }, "A-Series (Kabini)", "TSMC N28" }, + { 15, 0, -1, 22, 0, -1, -1, -1, { "A[46]-5###", 4 }, "A-Series (Kabini)", "TSMC N28" }, + /* 2nd-gen, Puma core (2013): */ + { 15, 0, -1, 22, 48, 2, -1, -1, { "E1 Micro-62##T", 8 }, "E-Series (Mullins)", "GF 28SHP" }, + { 15, 0, -1, 22, 48, 4, -1, -1, { "A4 Micro-64##T", 8 }, "A-Series (Mullins)", "GF 28SHP" }, + { 15, 0, -1, 22, 48, 4, -1, -1, { "A10 Micro-67##T", 8 }, "A-Series (Mullins)", "GF 28SHP" }, + { 15, 0, 1, 22, 48, -1, -1, -1, { "E[12]-6###", 4 }, "E-Series (Beema)", "GF 28SHP" }, + { 15, 0, 1, 22, 48, -1, -1, -1, { "A[468]-6###", 4 }, "A-Series (Beema)", "GF 28SHP" }, + { 15, 0, 1, 22, 48, -1, -1, -1, { "GX-###", 4 }, "G-Series (Steppe Eagle)", "GF 28SHP" }, + + /* Family 17h */ + /* Zen (2017) => https://en.wikichip.org/wiki/amd/microarchitectures/zen */ + { 15, -1, -1, 23, 1, -1, -1, -1, { "EPYC 7##1", 4 }, "EPYC (Naples)", "GF 14LP" }, + { 15, -1, -1, 23, 1, -1, -1, -1, { "Threadripper 1###", 4 }, "Threadripper (Whitehaven)", "GF 14LP" }, + { 15, -1, -1, 23, 1, -1, -1, -1, { "Ryzen 7 PRO 1###", 8 }, "Ryzen 7 PRO (Summit Ridge)", "GF 14LP" }, + { 15, -1, -1, 23, 1, -1, -1, -1, { "Ryzen 7 1###", 6 }, "Ryzen 7 (Summit Ridge)", "GF 14LP" }, + { 15, -1, -1, 23, 1, -1, -1, -1, { "Ryzen 5 PRO 1###", 8 }, "Ryzen 5 PRO (Summit Ridge)", "GF 14LP" }, + { 15, -1, -1, 23, 1, -1, -1, -1, { "Ryzen 5 1###", 6 }, "Ryzen 5 (Summit Ridge)", "GF 14LP" }, + { 15, -1, -1, 23, 1, -1, -1, -1, { "Ryzen 3 PRO 1###", 8 }, "Ryzen 3 PRO (Summit Ridge)", "GF 14LP" }, + { 15, -1, -1, 23, 1, -1, -1, -1, { "Ryzen 3 1###", 6 }, "Ryzen 3 (Summit Ridge)", "GF 14LP" }, + { 15, -1, -1, 23, 17, -1, -1, -1, { "Ryzen PRO 7 2###", 8 }, "Ryzen 7 PRO (Raven Ridge)", "GF 14LP" }, + { 15, -1, -1, 23, 17, -1, -1, -1, { "Ryzen 7 2###", 6 }, "Ryzen 7 (Raven Ridge)", "GF 14LP" }, + { 15, -1, -1, 23, 17, -1, -1, -1, { "Ryzen PRO 5 2###", 8 }, "Ryzen 5 PRO (Raven Ridge)", "GF 14LP" }, + { 15, -1, -1, 23, 17, -1, -1, -1, { "Ryzen 5 2###", 6 }, "Ryzen 5 (Raven Ridge)", "GF 14LP" }, + { 15, -1, -1, 23, 17, -1, -1, -1, { "Ryzen PRO 3 2###", 8 }, "Ryzen 3 PRO (Raven Ridge)", "GF 14LP" }, + { 15, -1, -1, 23, 17, -1, -1, -1, { "Ryzen 3 2###", 6 }, "Ryzen 3 (Raven Ridge)", "GF 14LP" }, + { 15, -1, -1, 23, 17, -1, -1, -1, { "Athlon", 2 }, "Athlon (Raven Ridge)", "GF 14LP" }, + { 15, -1, -1, 23, 32, -1, -1, -1, { "Ryzen 3 3###", 6 }, "Ryzen 3 (Dali)", "GF 14LP" }, + { 15, -1, -1, 23, 32, -1, -1, -1, { "Athlon", 2 }, "Athlon (Dali)", "GF 14LP" }, + { 15, -1, 1, 23, 32, -1, -1, -1, { "", 0 }, "Dali", "GF 14LP" }, /* AMD 3020e */ + /* Zen+ (2018) => https://en.wikichip.org/wiki/amd/microarchitectures/zen%2B */ + { 15, -1, -1, 23, 8, -1, -1, -1, { "Threadripper 2###", 4 }, "Threadripper (Colfax)", "GF 12LP" }, + { 15, -1, -1, 23, 8, -1, -1, -1, { "Ryzen 7 PRO 2###", 8 }, "Ryzen 7 PRO (Pinnacle Ridge)", "GF 12LP" }, + { 15, -1, -1, 23, 8, -1, -1, -1, { "Ryzen 7 2###", 6 }, "Ryzen 7 (Pinnacle Ridge)", "GF 12LP" }, + { 15, -1, -1, 23, 8, -1, -1, -1, { "Ryzen 5 PRO 2###", 8 }, "Ryzen 5 PRO (Pinnacle Ridge)", "GF 12LP" }, + { 15, -1, -1, 23, 8, -1, -1, -1, { "Ryzen 5 2###", 6 }, "Ryzen 5 (Pinnacle Ridge)", "GF 12LP" }, + { 15, -1, -1, 23, 8, -1, -1, -1, { "Ryzen 3 PRO 2###", 8 }, "Ryzen 3 PRO (Pinnacle Ridge)", "GF 12LP" }, + { 15, -1, -1, 23, 8, -1, -1, -1, { "Ryzen 3 2###", 6 }, "Ryzen 3 (Pinnacle Ridge)", "GF 12LP" }, + { 15, -1, -1, 23, 24, -1, -1, -1, { "Ryzen 7 PRO 3###", 8 }, "Ryzen 7 PRO (Picasso)", "GF 12LP" }, + { 15, -1, -1, 23, 24, -1, -1, -1, { "Ryzen 7 3###", 6 }, "Ryzen 7 (Picasso)", "GF 12LP" }, + { 15, -1, -1, 23, 24, -1, -1, -1, { "Ryzen 5 PRO 3###", 8 }, "Ryzen 5 PRO (Picasso)", "GF 12LP" }, + { 15, -1, -1, 23, 24, -1, -1, -1, { "Ryzen 5 3###", 6 }, "Ryzen 5 (Picasso)", "GF 12LP" }, + { 15, -1, -1, 23, 24, -1, -1, -1, { "Ryzen 3 PRO 3###", 8 }, "Ryzen 3 PRO (Picasso)", "GF 12LP" }, + { 15, -1, -1, 23, 24, -1, -1, -1, { "Ryzen 3 3###", 6 }, "Ryzen 3 (Picasso)", "GF 12LP" }, + { 15, -1, -1, 23, 24, -1, -1, -1, { "Athlon", 2 }, "Athlon (Picasso)", "GF 12LP" }, + /* Zen 2 (2019) => https://en.wikichip.org/wiki/amd/microarchitectures/zen_2 */ + { 15, -1, -1, 23, 49, -1, -1, -1, { "EPYC 7##2", 4 }, "EPYC (Rome)", "TSMC N7FF" }, + { 15, -1, -1, 23, 49, -1, -1, -1, { "Threadripper PRO 3###WX", 10 }, "Threadripper PRO (Castle Peak)", "TSMC N7FF" }, + { 15, -1, -1, 23, 49, -1, -1, -1, { "Threadripper 3###X", 6 }, "Threadripper (Castle Peak)", "TSMC N7FF" }, + { 15, -1, -1, 23, 113, -1, -1, -1, { "Ryzen 9 PRO 3###", 8 }, "Ryzen 9 PRO (Matisse)", "TSMC N7FF" }, + { 15, -1, -1, 23, 113, -1, -1, -1, { "Ryzen 9 3###", 6 }, "Ryzen 9 (Matisse)", "TSMC N7FF" }, + { 15, -1, -1, 23, 113, -1, -1, -1, { "Ryzen 7 PRO 3###", 8 }, "Ryzen 7 PRO (Matisse)", "TSMC N7FF" }, + { 15, -1, -1, 23, 113, -1, -1, -1, { "Ryzen 7 3###", 6 }, "Ryzen 7 (Matisse)", "TSMC N7FF" }, + { 15, -1, -1, 23, 113, -1, -1, -1, { "Ryzen 5 PRO 3###", 8 }, "Ryzen 5 PRO (Matisse)", "TSMC N7FF" }, + { 15, -1, -1, 23, 113, -1, -1, -1, { "Ryzen 5 3###", 6 }, "Ryzen 5 (Matisse)", "TSMC N7FF" }, + { 15, -1, -1, 23, 113, -1, -1, -1, { "Ryzen 3 PRO 3###", 8 }, "Ryzen 3 PRO (Matisse)", "TSMC N7FF" }, + { 15, -1, -1, 23, 113, -1, -1, -1, { "Ryzen 3 3###", 6 }, "Ryzen 3 (Matisse)", "TSMC N7FF" }, + { 15, -1, -1, 23, 96, -1, -1, -1, { "Ryzen 9 PRO 4###", 8 }, "Ryzen 9 PRO (Renoir)", "TSMC N7FF" }, + { 15, -1, -1, 23, 96, -1, -1, -1, { "Ryzen 9 4###", 6 }, "Ryzen 9 (Renoir)", "TSMC N7FF" }, + { 15, -1, -1, 23, 96, -1, -1, -1, { "Ryzen 7 PRO 4###", 8 }, "Ryzen 7 PRO (Renoir)", "TSMC N7FF" }, + { 15, -1, -1, 23, 96, -1, -1, -1, { "Ryzen 7 4###", 6 }, "Ryzen 7 (Renoir)", "TSMC N7FF" }, + { 15, -1, -1, 23, 96, -1, -1, -1, { "Ryzen 5 PRO 4###", 8 }, "Ryzen 5 PRO (Renoir)", "TSMC N7FF" }, + { 15, -1, -1, 23, 96, -1, -1, -1, { "Ryzen 5 4###", 6 }, "Ryzen 5 (Renoir)", "TSMC N7FF" }, + { 15, -1, -1, 23, 96, -1, -1, -1, { "Ryzen 3 PRO 4###", 8 }, "Ryzen 3 PRO (Renoir)", "TSMC N7FF" }, + { 15, -1, -1, 23, 96, -1, -1, -1, { "Ryzen 3 4###", 6 }, "Ryzen 3 (Renoir)", "TSMC N7FF" }, + { 15, -1, -1, 23, 104, -1, -1, -1, { "Ryzen 7 5###", 6 }, "Ryzen 7 (Lucienne)", "TSMC N7FF" }, + { 15, -1, -1, 23, 104, -1, -1, -1, { "Ryzen 5 5###", 6 }, "Ryzen 5 (Lucienne)", "TSMC N7FF" }, + { 15, -1, -1, 23, 104, -1, -1, -1, { "Ryzen 3 5###", 6 }, "Ryzen 3 (Lucienne)", "TSMC N7FF" }, + { 15, -1, -1, 23, 71, -1, -1, -1, { "Desktop Kit", 4 }, "Desktop Kit (Zen 2)", "TSMC N7FF" }, /* 4700S Desktop Kit */ + { 15, -1, -1, 23, 132, -1, -1, -1, { "Desktop Kit", 4 }, "Desktop Kit (Zen 2)", "TSMC N7FF" }, /* 4800S Desktop Kit */ + { 15, -1, 2, 23, 144, -1, -1, -1, { "Custom APU", 4 }, "Van Gogh", "TSMC N7FF" }, /* Custom APU 0405 */ + { 15, -1, 0, 23, 145, -1, -1, -1, { "Custom APU", 4 }, "Van Gogh", "TSMC N7FF" }, /* Custom APU 0932 */ + { 15, -1, -1, 23, 160, -1, -1, -1, { "Ryzen 5 7###", 6 }, "Ryzen 5 (Mendocino)", "TSMC N6" }, + { 15, -1, -1, 23, 160, -1, -1, -1, { "Ryzen 3 7###", 6 }, "Ryzen 3 (Mendocino)", "TSMC N6" }, + { 15, -1, -1, 23, 160, -1, -1, -1, { "Athlon", 2 }, "Athlon (Mendocino)", "TSMC N6" }, + + /* Family 18h */ + /* Zen Architecture for Hygon (2018) => https://en.wikichip.org/wiki/hygon/microarchitectures/dhyana */ + { 15, -1, -1, 24, 0, -1, -1, -1, { "C86", 2 }, "C86 (Dhyana)", UNKN_STR }, + + /* Family 19h */ + /* Zen 3 (2020) => https://en.wikichip.org/wiki/amd/microarchitectures/zen_3 */ + { 15, -1, -1, 25, 1, -1, -1, -1, { "EPYC 7##3", 4 }, "EPYC (Milan)", "TSMC N7FF" }, + { 15, -1, -1, 25, 8, -1, -1, -1, { "Threadripper PRO 5###WX", 10 }, "Threadripper PRO (Chagall)", "TSMC N7FF" }, + { 15, -1, -1, 25, 33, -1, -1, -1, { "Ryzen 9 PRO 5###", 8 }, "Ryzen 9 PRO (Vermeer)", "TSMC N7FF" }, + { 15, -1, -1, 25, 33, -1, -1, -1, { "Ryzen 9 5###", 6 }, "Ryzen 9 (Vermeer)", "TSMC N7FF" }, + { 15, -1, -1, 25, 33, -1, -1, -1, { "Ryzen 7 PRO 5###", 8 }, "Ryzen 7 PRO (Vermeer)", "TSMC N7FF" }, + { 15, -1, -1, 25, 33, -1, -1, -1, { "Ryzen 7 5###", 6 }, "Ryzen 7 (Vermeer)", "TSMC N7FF" }, + { 15, -1, -1, 25, 33, -1, -1, -1, { "Ryzen 5 PRO 5###", 8 }, "Ryzen 5 PRO (Vermeer)", "TSMC N7FF" }, + { 15, -1, -1, 25, 33, -1, -1, -1, { "Ryzen 5 5###", 6 }, "Ryzen 5 (Vermeer)", "TSMC N7FF" }, + { 15, -1, -1, 25, 33, -1, -1, -1, { "Ryzen 3 PRO 5###", 8 }, "Ryzen 3 PRO (Vermeer)", "TSMC N7FF" }, + { 15, -1, -1, 25, 33, -1, -1, -1, { "Ryzen 3 5###", 6 }, "Ryzen 3 (Vermeer)", "TSMC N7FF" }, + { 15, -1, -1, 25, 80, -1, -1, -1, { "Ryzen 9 PRO 5##0[HU]", 10 }, "Ryzen 9 PRO (Cezanne)", "TSMC N7FF" }, + { 15, -1, -1, 25, 80, -1, -1, -1, { "Ryzen 9 5##0[HU]", 8 }, "Ryzen 9 (Cezanne)", "TSMC N7FF" }, + { 15, -1, -1, 25, 80, -1, -1, -1, { "Ryzen 7 PRO 5##0[HU]", 10 }, "Ryzen 7 PRO (Cezanne)", "TSMC N7FF" }, + { 15, -1, -1, 25, 80, -1, -1, -1, { "Ryzen 7 5##0[HU]", 8 }, "Ryzen 7 (Cezanne)", "TSMC N7FF" }, + { 15, -1, -1, 25, 80, -1, -1, -1, { "Ryzen 5 PRO 5##0[HU]", 10 }, "Ryzen 5 PRO (Cezanne)", "TSMC N7FF" }, + { 15, -1, -1, 25, 80, -1, -1, -1, { "Ryzen 5 5##0[HU]", 8 }, "Ryzen 5 (Cezanne)", "TSMC N7FF" }, + { 15, -1, -1, 25, 80, -1, -1, -1, { "Ryzen 3 PRO 5##0[HU]", 10 }, "Ryzen 3 PRO (Cezanne)", "TSMC N7FF" }, + { 15, -1, -1, 25, 80, -1, -1, -1, { "Ryzen 3 5##0[HU]", 8 }, "Ryzen 3 (Cezanne)", "TSMC N7FF" }, + { 15, -1, -1, 25, 80, -1, -1, -1, { "Ryzen 7 5##5U", 8 }, "Ryzen 7 (Barceló)", "TSMC N7FF" }, /* Ryzen 7 5825U */ + { 15, -1, -1, 25, 80, -1, -1, -1, { "Ryzen 5 5##5U", 8 }, "Ryzen 5 (Barceló)", "TSMC N7FF" }, /* Ryzen 5 5625U */ + { 15, -1, -1, 25, 80, -1, -1, -1, { "Ryzen 3 PRO 5##5U", 10 }, "Ryzen 3 PRO (Barceló)", "TSMC N7FF" }, /* Ryzen 3 PRO 5475U */ + { 15, -1, -1, 25, 80, -1, -1, -1, { "Ryzen 3 5##5C", 8 }, "Ryzen 3 (Barceló)", "TSMC N7FF" }, /* Ryzen 3 5125C */ + /* Zen 3+ (2022) */ + { 15, -1, -1, 25, 68, -1, -1, -1, { "Ryzen 9 PRO 6###", 8 }, "Ryzen 9 PRO (Rembrandt)", "TSMC N6" }, + { 15, -1, -1, 25, 68, -1, -1, -1, { "Ryzen 9 6###", 6 }, "Ryzen 9 (Rembrandt)", "TSMC N6" }, + { 15, -1, -1, 25, 68, -1, -1, -1, { "Ryzen 7 PRO 6###", 8 }, "Ryzen 7 PRO (Rembrandt)", "TSMC N6" }, + { 15, -1, -1, 25, 68, -1, -1, -1, { "Ryzen 7 6###", 6 }, "Ryzen 7 (Rembrandt)", "TSMC N6" }, + { 15, -1, -1, 25, 68, -1, -1, -1, { "Ryzen 5 PRO 6###", 8 }, "Ryzen 5 PRO (Rembrandt)", "TSMC N6" }, + { 15, -1, -1, 25, 68, -1, -1, -1, { "Ryzen 5 6###", 6 }, "Ryzen 5 (Rembrandt)", "TSMC N6" }, + { 15, -1, -1, 25, 68, -1, -1, -1, { "Ryzen 3 PRO 6###", 8 }, "Ryzen 3 PRO (Rembrandt)", "TSMC N6" }, + { 15, -1, -1, 25, 68, -1, -1, -1, { "Ryzen 3 6###", 6 }, "Ryzen 3 (Rembrandt)", "TSMC N6" }, + { 15, -1, -1, 25, 68, -1, -1, -1, { "Ryzen 7 7###", 6 }, "Ryzen 7 (Rembrandt-R)", "TSMC N6" }, + { 15, -1, -1, 25, 68, -1, -1, -1, { "Ryzen 5 7###", 6 }, "Ryzen 5 (Rembrandt-R)", "TSMC N6" }, + { 15, -1, -1, 25, 68, -1, -1, -1, { "Ryzen 3 7###", 6 }, "Ryzen 3 (Rembrandt-R)", "TSMC N6" }, + /* Zen 4 (2022) => https://en.wikichip.org/wiki/amd/microarchitectures/zen_4 */ + { 15, -1, -1, 25, 17, -1, -1, -1, { "EPYC 9##4", 4 }, "EPYC (Genoa)", "TSMC N5" }, + { 15, -1, -1, 25, 24, -1, -1, -1, { "Threadripper PRO 7###WX", 10 }, "Threadripper PRO (Storm Peak)", "TSMC N5" }, + { 15, -1, -1, 25, 24, -1, -1, -1, { "Threadripper 7###X", 6 }, "Threadripper (Storm Peak)", "TSMC N5" }, + /* => Raphael (7000 series, Zen 4/RDNA2 based) */ + { 15, -1, 2, 25, 97, -1, -1, -1, { "Ryzen 9 7###", 6 }, "Ryzen 9 (Raphael)", "TSMC N5" }, + { 15, -1, 2, 25, 97, -1, -1, -1, { "Ryzen 7 7###", 6 }, "Ryzen 7 (Raphael)", "TSMC N5" }, + { 15, -1, 2, 25, 97, -1, -1, -1, { "Ryzen 5 7###", 6 }, "Ryzen 5 (Raphael)", "TSMC N5" }, + { 15, -1, 2, 25, 97, -1, -1, -1, { "Ryzen 3 7###", 6 }, "Ryzen 3 (Raphael)", "TSMC N5" }, + /* => Dragon Range (7045 series, Zen 4/RDNA2 based) */ + { 15, -1, -1, 25, 97, -1, -1, -1, { "Ryzen 9 7###H", 8 }, "Ryzen 9 (Dragon Range)", "TSMC N5" }, + { 15, -1, -1, 25, 97, -1, -1, -1, { "Ryzen 7 7###H", 8 }, "Ryzen 7 (Dragon Range)", "TSMC N5" }, + { 15, -1, -1, 25, 97, -1, -1, -1, { "Ryzen 5 7###H", 8 }, "Ryzen 5 (Dragon Range)", "TSMC N5" }, + /* => Phoenix (7040 series, Zen 4/RDNA3/XDNA based) */ + { 15, -1, -1, 25, 116, -1, -1, -1, { "Ryzen 9 PRO 7###[HU]", 10 }, "Ryzen 9 PRO (Phoenix)", "TSMC N4" }, + { 15, -1, -1, 25, 116, -1, -1, -1, { "Ryzen 9 7###[HU]", 8 }, "Ryzen 9 (Phoenix)", "TSMC N4" }, + { 15, -1, -1, 25, 116, -1, -1, -1, { "Ryzen 7 PRO 7###[HU]", 10 }, "Ryzen 7 PRO (Phoenix)", "TSMC N4" }, + { 15, -1, -1, 25, 116, -1, -1, -1, { "Ryzen 7 7###[HU]", 8 }, "Ryzen 7 (Phoenix)", "TSMC N4" }, + { 15, -1, -1, 25, 116, -1, -1, -1, { "Ryzen 5 PRO 7###[HU]", 10 }, "Ryzen 5 PRO (Phoenix)", "TSMC N4" }, + { 15, -1, -1, 25, 116, -1, -1, -1, { "Ryzen 5 7###[HU]", 8 }, "Ryzen 5 (Phoenix)", "TSMC N4" }, + { 15, -1, -1, 25, 116, -1, -1, -1, { "Ryzen 3 PRO 7###[HU]", 10 }, "Ryzen 3 PRO (Phoenix)", "TSMC N4" }, + { 15, -1, -1, 25, 116, -1, -1, -1, { "Ryzen 3 7###[HU]", 8 }, "Ryzen 3 (Phoenix)", "TSMC N4" }, + { 15, -1, -1, 25, 116, -1, -1, -1, { "Ryzen Z1", 4 }, "Ryzen Z1 (Phoenix)", "TSMC N4" }, + /* => Phoenix (8000 series, Zen 4 based) */ + { 15, -1, -1, 25, 117, -1, -1, -1, { "Ryzen 7 8###F", 8 }, "Ryzen 7 (Phoenix)", "TSMC N4" }, + { 15, -1, -1, 25, 117, -1, -1, -1, { "Ryzen 5 8###F", 8 }, "Ryzen 5 (Phoenix)", "TSMC N4" }, + /* => Phoenix (8000 series with Radeon Graphics, Zen 4/RDNA3/XDNA based) */ + { 15, -1, -1, 25, 117, -1, -1, -1, { "Ryzen 9 PRO 8###G", 10 }, "Ryzen 9 PRO (Phoenix)", "TSMC N4" }, + { 15, -1, -1, 25, 117, -1, -1, -1, { "Ryzen 9 8###G", 8 }, "Ryzen 9 (Phoenix)", "TSMC N4" }, + { 15, -1, -1, 25, 117, -1, -1, -1, { "Ryzen 7 PRO 8###G", 10 }, "Ryzen 7 PRO (Phoenix)", "TSMC N4" }, + { 15, -1, -1, 25, 117, -1, -1, -1, { "Ryzen 7 8###G", 8 }, "Ryzen 7 (Phoenix)", "TSMC N4" }, + { 15, -1, -1, 25, 117, -1, -1, -1, { "Ryzen 5 PRO 8###G", 10 }, "Ryzen 5 PRO (Phoenix)", "TSMC N4" }, + { 15, -1, -1, 25, 117, -1, -1, -1, { "Ryzen 5 8###G", 8 }, "Ryzen 5 (Phoenix)", "TSMC N4" }, + { 15, -1, -1, 25, 117, -1, -1, -1, { "Ryzen 3 PRO 8###G", 10 }, "Ryzen 3 PRO (Phoenix)", "TSMC N4" }, + { 15, -1, -1, 25, 117, -1, -1, -1, { "Ryzen 3 8###G", 8 }, "Ryzen 3 (Phoenix)", "TSMC N4" }, + /* => Hawk Point (8040 series, Zen 4/RDNA3/XDNA based) */ + { 15, -1, -1, 25, 117, -1, -1, -1, { "Ryzen 9 PRO 8###[HU]", 10 }, "Ryzen 9 PRO (Hawk Point)", "TSMC N4" }, + { 15, -1, -1, 25, 117, -1, -1, -1, { "Ryzen 9 8###[HU]", 8 }, "Ryzen 9 (Hawk Point)", "TSMC N4" }, + { 15, -1, -1, 25, 117, -1, -1, -1, { "Ryzen 7 PRO 8###[HU]", 10 }, "Ryzen 7 PRO (Hawk Point)", "TSMC N4" }, + { 15, -1, -1, 25, 117, -1, -1, -1, { "Ryzen 7 8###[HU]", 8 }, "Ryzen 7 (Hawk Point)", "TSMC N4" }, + { 15, -1, -1, 25, 117, -1, -1, -1, { "Ryzen 5 PRO 8###[HU]", 10 }, "Ryzen 5 PRO (Hawk Point)", "TSMC N4" }, + { 15, -1, -1, 25, 117, -1, -1, -1, { "Ryzen 5 8###[HU]", 8 }, "Ryzen 5 (Hawk Point)", "TSMC N4" }, + { 15, -1, -1, 25, 117, -1, -1, -1, { "Ryzen 3 PRO 8###[HU]", 10 }, "Ryzen 3 PRO (Hawk Point)", "TSMC N4" }, + { 15, -1, -1, 25, 117, -1, -1, -1, { "Ryzen 3 8###[HU]", 8 }, "Ryzen 3 (Hawk Point)", "TSMC N4" }, + /* Zen 5 (2024) => https://en.wikichip.org/wiki/amd/microarchitectures/zen_5 */ + { 15, -1, -1, 26, 2, -1, -1, -1, { "EPYC 9##5", 4 }, "EPYC (Turin)", "TSMC N4X" }, + { 15, -1, -1, 26, 17, -1, -1, -1, { "EPYC 9##5", 4 }, "EPYC (Turin Dense)", "TSMC N3E" }, + { 15, -1, -1, 26, 8, -1, -1, -1, { "Threadripper PRO 9###WX", 10 }, "Threadripper PRO (Shimada Peak)", "TSMC N4" }, + { 15, -1, -1, 26, 8, -1, -1, -1, { "Threadripper 9###X", 6 }, "Threadripper (Shimada Peak)", "TSMC N4" }, + /* => Granite Ridge (9000 series, Zen 5 based) */ + { 15, -1, -1, 26, 68, -1, -1, -1, { "Ryzen 9 PRO 9###", 8 }, "Ryzen 9 PRO (Granite Ridge)", "TSMC N4" }, + { 15, -1, -1, 26, 68, -1, -1, -1, { "Ryzen 9 9###", 6 }, "Ryzen 9 (Granite Ridge)", "TSMC N4" }, + { 15, -1, -1, 26, 68, -1, -1, -1, { "Ryzen 7 PRO 9###", 8 }, "Ryzen 7 PRO (Granite Ridge)", "TSMC N4" }, + { 15, -1, -1, 26, 68, -1, -1, -1, { "Ryzen 7 9###", 6 }, "Ryzen 7 (Granite Ridge)", "TSMC N4" }, + { 15, -1, -1, 26, 68, -1, -1, -1, { "Ryzen 5 PRO 9###", 8 }, "Ryzen 5 PRO (Granite Ridge)", "TSMC N4" }, + { 15, -1, -1, 26, 68, -1, -1, -1, { "Ryzen 5 9###", 6 }, "Ryzen 5 (Granite Ridge)", "TSMC N4" }, + { 15, -1, -1, 26, 68, -1, -1, -1, { "Ryzen 3 PRO 9###", 8 }, "Ryzen 3 PRO (Granite Ridge)", "TSMC N4" }, + { 15, -1, -1, 26, 68, -1, -1, -1, { "Ryzen 3 9###", 6 }, "Ryzen 3 (Granite Ridge)", "TSMC N4" }, + /* => Strix Point and Krackan Point (Zen 5/RDNA3.5/XDNA2 based) */ + { 15, -1, -1, 26, 36, -1, -1, -1, { "Ryzen AI 9 HX PRO", 10 }, "Ryzen AI 9 PRO (Strix Point)", "TSMC N4P" }, + { 15, -1, -1, 26, 36, -1, -1, -1, { "Ryzen AI 9", 6 }, "Ryzen AI 9 (Strix Point)", "TSMC N4P" }, + { 15, -1, -1, 26, 36, -1, -1, -1, { "Ryzen AI 7 PRO", 8 }, "Ryzen AI 7 PRO (Strix Point)", "TSMC N4P" }, /* Ryzen AI 7 PRO 360 */ + { 15, -1, -1, 26, 96, -1, -1, -1, { "Ryzen AI 7 PRO", 8 }, "Ryzen AI 7 PRO (Krackan Point)", "TSMC N4P" }, /* Ryzen AI 7 PRO 350 */ + { 15, -1, -1, 26, 96, -1, -1, -1, { "Ryzen AI 7", 6 }, "Ryzen AI 7 (Krackan Point)", "TSMC N4P" }, /* Ryzen AI 7 350 */ + { 15, -1, -1, 26, 96, -1, -1, -1, { "Ryzen AI 5 PRO", 8 }, "Ryzen AI 5 PRO (Krackan Point)", "TSMC N4P" }, /* Ryzen AI 5 PRO 340 */ + { 15, -1, -1, 26, 96, -1, -1, -1, { "Ryzen AI 5", 6 }, "Ryzen AI 5 (Krackan Point)", "TSMC N4P" }, /* Ryzen AI 5 340 */ + /* => Strix Halo (Zen 5/RDNA3.5/XDNA2 based) */ + { 15, -1, -1, 26, 112, -1, -1, -1, { "Ryzen AI MAX+ PRO", 10 }, "Ryzen AI MAX+ PRO (Strix Halo)", "TSMC N4P" }, /* Ryzen AI MAX+ PRO 395 */ + { 15, -1, -1, 26, 112, -1, -1, -1, { "Ryzen AI MAX+", 8 }, "Ryzen AI MAX+ (Strix Halo)", "TSMC N4P" }, /* Ryzen AI MAX+ 395 */ + { 15, -1, -1, 26, 112, -1, -1, -1, { "Ryzen AI MAX PRO", 8 }, "Ryzen AI MAX PRO (Strix Halo)", "TSMC N4P" }, + { 15, -1, -1, 26, 112, -1, -1, -1, { "Ryzen AI MAX", 6 }, "Ryzen AI MAX (Strix Halo)", "TSMC N4P" }, +// F M S EF EM #cores L2$ L3$ Pattern Codename Technology +}; + +/********************************************************************************** */ + +// https://github.com/anrieff/libcpuid/blob/ff6b7500351293259ca808783ee81e8ab5b7c0cb/libcpuid/recog_centaur.c +/* + * Copyright 2023 Veselin Georgiev, + * anrieffNOSPAM @ mgail_DOT.com (convert to gmail) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +const struct match_entry_t cpudb_centaur[] = { +// F M S EF EM #cores L2$ L3$ Pattern Codename Technology + { -1, -1, -1, -1, -1, -1, -1, -1, { "", 0 }, "Unknown Centaur CPU", "" }, +// F M S EF EM #cores L2$ L3$ Pattern Codename Technology + + + /* VIA */ +// F M S EF EM #cores L2$ L3$ Pattern Codename Technology + { 6, -1, -1, -1, -1, -1, -1, -1, { "VIA", 2 }, "Unknown VIA CPU", "" }, + + /* Samuel (2000, 180 nm) */ + { 6, 6, -1, -1, -1, -1, -1, -1, { "VIA Samuel", 4 }, "VIA Cyrix III (Samuel)", "180 nm" }, + /* Samuel 2 (2001, 150 nm) */ + { 6, 7, -1, -1, -1, -1, -1, -1, { "VIA Samuel 2", 6 }, "VIA C3 (Samuel 2)", "150 nm" }, + /* Ezra (2001, 130 nm) */ + { 6, 7, -1, -1, -1, -1, -1, -1, { "VIA Ezra", 4 }, "VIA C3 (Ezra)", "130 nm" }, + { 6, 8, -1, -1, -1, -1, -1, -1, { "VIA C3 Ezra", 6 }, "VIA C3 (Ezra-T)", "130 nm" }, + /* Nehemiah (2003, 130 nm) */ + { 6, 9, -1, -1, -1, -1, -1, -1, { "VIA Nehemiah", 4 }, "VIA C3 (Nehemiah)", "130 nm" }, + /* Esther (2005, 90 nm) */ + { 6, 10, -1, -1, -1, -1, -1, -1, { "VIA Esther", 4 }, "VIA C7 (Esther)", "90 nm" }, + { 6, 13, -1, -1, -1, -1, -1, -1, { "VIA C7-M", 4 }, "VIA C7-M (Esther)", "90 nm" }, + /* Isaiah (2008, 65 nm) */ + { 6, 15, -1, -1, -1, -1, -1, -1, { "VIA Nano", 4 }, "VIA Nano (Isaiah)", "65 nm" }, + { 6, 15, -1, -1, -1, 1, -1, -1, { "VIA Nano", 4 }, "VIA Nano (Isaiah)", "65 nm" }, + { 6, 15, -1, -1, -1, 2, -1, -1, { "VIA Nano", 4 }, "VIA Nano X2 (Isaiah)", "65 nm" }, + { 6, 15, -1, -1, -1, -1, -1, -1, { "VIA QuadCore", 4 }, "VIA Nano X4 (Isaiah)", "65 nm" }, + { 6, 15, -1, -1, -1, 4, -1, -1, { "VIA Eden X4", 6 }, "VIA Eden X4 (Isaiah)", "65 nm" }, +// F M S EF EM #cores L2$ L3$ Pattern Codename Technology + + + /* Zhaoxin */ +// F M S EF EM #cores L2$ L3$ Pattern Codename Technology + { 7, -1, -1, -1, -1, -1, -1, -1, {"ZHAOXIN", 2 }, "Unknown Zhaoxin CPU", "" }, + + /* Zhangjiang (2015, 28 nm) */ + { 7, -1, -1, -1, 15, -1, -1, -1, { "ZHAOXIN KaisHeng KH-C", 8 }, "Zhaoxin KaisHeng (ZhangJiang)", "28 nm" }, // C+ (4000) + { 7, -1, -1, -1, 15, -1, -1, -1, { "ZHAOXIN KaiXian ZX-C", 8 }, "Zhaoxin KaiXian (ZhangJiang)", "28 nm" }, // C/C+ (4000) + /* WuDaoKou (2017, 28 nm) */ + { 7, -1, -1, -1, 27, -1, -1, -1, { "ZHAOXIN KaisHeng KH-20###", 8 }, "Zhaoxin KaisHeng (WuDaoKou)", "28 nm" }, // KH (20000) + { 7, -1, -1, -1, 27, -1, -1, -1, { "ZHAOXIN KaiXian KX-5###", 8 }, "Zhaoxin KaiXian (WuDaoKou)", "28 nm" }, // KX (5000) + { 7, -1, -1, -1, 27, -1, -1, -1, { "ZHAOXIN KaiXian KX-U5###", 8 }, "Zhaoxin KaiXian (WuDaoKou)", "28 nm" }, // KX (U5000) + /* LuJiaZui (2019, 16 nm) */ + { 7, -1, -1, -1, 59, -1, -1, -1, { "ZHAOXIN KaisHeng KH-30###", 8 }, "Zhaoxin KaisHeng (LuJiaZui)", "16 nm" }, // KH (30000) + { 7, -1, -1, -1, 59, -1, -1, -1, { "ZHAOXIN KaiXian KX-6###", 8 }, "Zhaoxin KaiXian (LuJiaZui)", "16 nm" }, // KX (6000) + { 7, -1, -1, -1, 59, -1, -1, -1, { "ZHAOXIN KaiXian KX-U6###", 8 }, "Zhaoxin KaiXian (LuJiaZui)", "16 nm" }, // KX (U6000) + /* Yongfeng (2022, 16 nm) */ + { 7, -1, -1, -1, 91, -1, -1, -1, { "ZHAOXIN KaisHeng KH-40###", 8 }, "Zhaoxin KaisHeng (Yongfeng)", "16 nm" }, // KH (40000) + { 7, -1, -1, -1, 91, -1, -1, -1, { "ZHAOXIN KaiXian KX-7###", 8 }, "Zhaoxin KaiXian (Yongfeng)", "16 nm" }, // KX (7000) +// F M S EF EM #cores L2$ L3$ Pattern Codename Technology +}; + +// clang-format on + +/////////////////////////////////////////////////////////////////////////////////////////////// + +static bool match_pattern_core(const char* p, const char* b) { + while (*p && *b) { + if (*p == '#') { + // '#' digit + if (!ffCharIsDigit(*b)) return false; + p++; b++; + } else if (*p == '[') { + // '[' chars + p++; + bool found = false; + while (*p && *p != ']') { + if (*p == *b) found = true; + p++; + } + if (!found) return false; + if (*p == ']') p++; + b++; + } else { + // char + if (*p != *b) return false; + p++; b++; + } + } + + // ignore suffix + return (*p == '\0'); +} + +static bool match_brand_pattern(const char* pattern, const char* brand) { + if (pattern[0] == '\0') return true; + if (brand[0] == '\0') return false; + + for (const char* b = brand; *b != '\0'; b++) { + if (match_pattern_core(pattern, b)) { + return true; + } + } + return false; +} + +bool ffCPUDetectX86Specific(FFCPUResult* cpu) { + // Ref: https://github.com/anrieff/libcpuid/blob/2e4456ae0165db3155da2e8fba92afd5c090ca1b/libcpuid/cpuid_main.c#L1096 + unsigned int eax, ebx, ecx, edx; + + // Vendor (CPUID Leaf 0) + if (!__get_cpuid(0, &eax, &ebx, &ecx, &edx)) { + return false; + } + + if (!cpu->vendor.length) { + ffStrbufEnsureFixedLengthFree(&cpu->vendor, 12); + memcpy(cpu->vendor.chars + 0, &ebx, 4); + memcpy(cpu->vendor.chars + 4, &edx, 4); + memcpy(cpu->vendor.chars + 8, &ecx, 4); + cpu->vendor.chars[12] = '\0'; + cpu->vendor.length = 12; + } + + // CPU Version Info (CPUID Leaf 1) + if (!__get_cpuid(1, &eax, &ebx, &ecx, &edx)) { + return false; + } + + int32_t family = (eax >> 8) & 0xF; + int32_t model = (eax >> 4) & 0xF; + int32_t stepping = eax & 0xF; + int32_t xfamily = (eax >> 20) & 0xFF; + + // https://github.com/anrieff/libcpuid/blob/2e4456ae0165db3155da2e8fba92afd5c090ca1b/libcpuid/cpuid_main.c#L1112 + int32_t ext_family = __builtin_expect(family < 0xF && ffStrbufEqualS(&cpu->vendor, "AuthenticAMD"), false) + ? family + : family + xfamily; + + int32_t xmodel = (eax >> 16) & 0xF; + int32_t ext_model = model + (xmodel << 4); + + const struct match_entry_t* matchtable = NULL; + uint32_t count = 0; + + if (ffStrbufEqualS(&cpu->vendor, "GenuineIntel")) { + matchtable = cpudb_intel; + count = ARRAY_SIZE(cpudb_intel); + } else if (ffStrbufEqualS(&cpu->vendor, "AuthenticAMD")) { + matchtable = cpudb_amd; + count = ARRAY_SIZE(cpudb_amd); + } else if (ffStrbufEqualS(&cpu->vendor, "CentaurHauls")) { + matchtable = cpudb_centaur; + count = ARRAY_SIZE(cpudb_centaur); + } else { + return false; + } + + const FFCPUX86MatchEntry* bestEntry = NULL; + int32_t bestScore = -1; + + for (uint32_t i = 0; i < count; i++) { + int score = 0; + const FFCPUX86MatchEntry* entry = &matchtable[i]; + + if (entry->family != family) { + continue; + } + + if (entry->model == model) { + score += 2; + } else if (entry->model != -1) { + continue; + } + + if (entry->stepping == stepping) { + score += 2; + } else if (entry->stepping != -1) { + continue; + } + + if (entry->ext_family == ext_family) { + score += 2; + } else if (entry->ext_family != -1) { + continue; + } + + if (entry->ext_model == ext_model) { + score += 2; + } else if (entry->ext_model != -1) { + continue; + } + + if (entry->brand.pattern[0] != '\0') { + if (match_brand_pattern(entry->brand.pattern, cpu->name.chars)) { + score += entry->brand.score; + } else { + continue; + } + } + + if (score > bestScore) { + bestScore = score; + bestEntry = entry; + } + } + + if (bestEntry && bestScore > 0) { + cpu->codeName = bestEntry->name; + cpu->technology = bestEntry->technology; + return true; + } + + return false; +} + +#endif diff --git a/src/detection/displayserver/displayserver.c b/src/detection/displayserver/displayserver.c index 58c8c89125..e913771097 100644 --- a/src/detection/displayserver/displayserver.c +++ b/src/detection/displayserver/displayserver.c @@ -42,7 +42,7 @@ FFDisplayResult* ffdsAppendDisplay( display->hdrStatus = FF_DISPLAY_HDR_STATUS_UNKNOWN; display->manufactureYear = 0; display->manufactureWeek = 0; - display->serial = 0; + ffStrbufInit(&display->serial); display->drrStatus = FF_DISPLAY_DRR_STATUS_UNKNOWN; return display; diff --git a/src/detection/displayserver/displayserver.h b/src/detection/displayserver/displayserver.h index fd88f370d9..53c0de3ea1 100644 --- a/src/detection/displayserver/displayserver.h +++ b/src/detection/displayserver/displayserver.h @@ -89,7 +89,7 @@ typedef struct FFDisplayResult { FFDisplayHdrStatus hdrStatus; uint16_t manufactureYear; uint16_t manufactureWeek; - uint32_t serial; + FFstrbuf serial; FFDisplayVrrStatus drrStatus; } FFDisplayResult; diff --git a/src/detection/displayserver/displayserver_apple.c b/src/detection/displayserver/displayserver_apple.c index 39ba604b38..a539cb3f95 100644 --- a/src/detection/displayserver/displayserver_apple.c +++ b/src/detection/displayserver/displayserver_apple.c @@ -9,6 +9,7 @@ #include #include #include +#include #ifdef MAC_OS_X_VERSION_10_15 extern Boolean CoreDisplay_Display_SupportsHDRMode(CGDirectDisplayID display) FF_A_WEAK_IMPORT; @@ -28,6 +29,7 @@ static void detectDisplays(FFDisplayServerResult* ds) { FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate(); for (uint32_t i = 0; i < screenCount; i++) { CGDirectDisplayID screen = screens[i]; + boolean_t builtin = CGDisplayIsBuiltin(screen); CGDisplayModeRef mode = CGDisplayCopyDisplayMode(screen); if (mode) { // https://github.com/glfw/glfw/commit/aab08712dd8142b642e2042e7b7ba563acd07a45 @@ -63,20 +65,37 @@ static void detectDisplays(FFDisplayServerResult* ds) { uint32_t physicalWidth = 0, physicalHeight = 0; uint32_t preferredWidth = 0, preferredHeight = 0; double preferredRefreshRate = 0; + FF_STRBUF_AUTO_DESTROY serial = ffStrbufCreate(); if (displayInfo) { - CFDictionaryRef productNames; - if (ffCfDictGetDict(displayInfo, CFSTR(kDisplayProductName), &productNames) == NULL) { - ffCfDictGetString(productNames, CFSTR("en_US"), &buffer); - } - // CGDisplayScreenSize reports invalid result for external displays on old Intel MacBook Pro CFDataRef edidRef = (CFDataRef) CFDictionaryGetValue(displayInfo, CFSTR(kIODisplayEDIDKey)); if (edidRef && CFGetTypeID(edidRef) == CFDataGetTypeID()) { const uint8_t* edidData = CFDataGetBytePtr(edidRef); uint32_t edidLength = (uint32_t) CFDataGetLength(edidRef); - if (edidLength >= 128) { + if (ffEdidIsValid(edidData, edidLength)) { ffEdidGetPhysicalSize(edidData, &physicalWidth, &physicalHeight); + ffEdidGetSerial(edidData, &serial); + } + } else if (!builtin && ffCfDictGetString(displayInfo, CFSTR(kIODisplayLocationKey), &buffer) == NULL) { + FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t ioDisplay = IORegistryEntryFromPath(MACH_PORT_NULL, buffer.chars); + ffStrbufClear(&buffer); + if (ioDisplay) { + FF_CFTYPE_AUTO_RELEASE CFDictionaryRef displayAttrRef = IORegistryEntryCreateCFProperty(ioDisplay, CFSTR("DisplayAttributes"), kCFAllocatorDefault, kNilOptions); + if (displayAttrRef && CFGetTypeID(displayAttrRef) == CFDictionaryGetTypeID()) { + CFDictionaryRef productAttrs; + if (ffCfDictGetDict(displayAttrRef, CFSTR("ProductAttributes"), &productAttrs) == NULL) { + ffCfDictGetString(productAttrs, CFSTR("AlphanumericSerialNumber"), &serial); + ffCfDictGetString(productAttrs, CFSTR("ProductName"), &buffer); + } + } + } + } + + if (!buffer.length) { + CFDictionaryRef productNames; + if (ffCfDictGetDict(displayInfo, CFSTR(kDisplayProductName), &productNames) == NULL) { + ffCfDictGetString(productNames, CFSTR("en_US"), &buffer); } } @@ -125,7 +144,7 @@ static void detectDisplays(FFDisplayServerResult* ds) { preferredRefreshRate, (uint32_t) CGDisplayRotation(screen), &buffer, - CGDisplayIsBuiltin(screen) ? FF_DISPLAY_TYPE_BUILTIN : FF_DISPLAY_TYPE_EXTERNAL, + builtin ? FF_DISPLAY_TYPE_BUILTIN : FF_DISPLAY_TYPE_EXTERNAL, CGDisplayIsMain(screen), (uint64_t) screen, physicalWidth, @@ -166,7 +185,14 @@ static void detectDisplays(FFDisplayServerResult* ds) { } #endif - display->serial = CGDisplaySerialNumber(screen); + if (serial.length) { + ffStrbufInitMove(&display->serial, &serial); + } else { + uint32_t int_serial = CGDisplaySerialNumber(screen); + if (int_serial != 0 && int_serial != 0xFFFFFFFF) { + ffStrbufSetF(&display->serial, "0x%08X", int_serial); + } + } if (displayInfo) { int value; diff --git a/src/detection/displayserver/displayserver_windows.c b/src/detection/displayserver/displayserver_windows.c index f92c144f90..5c4f57e630 100644 --- a/src/detection/displayserver/displayserver_windows.c +++ b/src/detection/displayserver/displayserver_windows.c @@ -196,7 +196,8 @@ static void detectDisplays(FFDisplayServerResult* ds) { } } if (edid.length > 0) { - ffEdidGetSerialAndManufactureDate(edid.data, &display->serial, &display->manufactureYear, &display->manufactureWeek); + ffEdidGetManufactureDate(edid.data, &display->manufactureYear, &display->manufactureWeek); + ffEdidGetSerial(edid.data, &display->serial); } display->drrStatus = path->flags & DISPLAYCONFIG_PATH_BOOST_REFRESH_RATE ? FF_DISPLAY_DRR_STATUS_ENABLED : FF_DISPLAY_DRR_STATUS_DISABLED; } diff --git a/src/detection/displayserver/linux/drm.c b/src/detection/displayserver/linux/drm.c index 43c6afcf4c..61c30cd140 100644 --- a/src/detection/displayserver/linux/drm.c +++ b/src/detection/displayserver/linux/drm.c @@ -2,6 +2,7 @@ #include "common/io.h" #include "common/edidHelper.h" #include "common/strutil.h" +#include "common/mallocHelper.h" #ifdef __linux__ #include @@ -43,8 +44,8 @@ static const char* drmParseSysfs(FFDisplayServerResult* result) { } } - unsigned width = 0, height = 0, physicalWidth = 0, physicalHeight = 0; - double refreshRate = 0; + uint32_t width = 0, height = 0, physicalWidth = 0, physicalHeight = 0, preferredWidth = 0, preferredHeight = 0; + double preferredRefreshRate = 0; FF_STRBUF_AUTO_DESTROY name = ffStrbufCreate(); ffStrbufSubstrBefore(&drmDir, drmDirWithDnameLength); @@ -58,33 +59,35 @@ static const char* drmParseSysfs(FFDisplayServerResult* result) { } } - uint8_t edidData[512]; - ssize_t edidLength = ffReadFileData(drmDir.chars, ARRAY_SIZE(edidData), edidData); - if (edidLength <= 0 || edidLength % 128 != 0) { - edidLength = 0; - ffStrbufSubstrBefore(&drmDir, drmDirWithDnameLength); - ffStrbufAppendS(&drmDir, "/modes"); + ffStrbufSubstrBefore(&drmDir, drmDirWithDnameLength); + ffStrbufAppendS(&drmDir, "/modes"); - char modes[32]; - if (ffReadFileData(drmDir.chars, ARRAY_SIZE(modes), modes) >= 3) { - sscanf(modes, "%ux%u", &width, &height); - ffStrbufAppendS(&name, plainName); - } - } else { + char modes[32]; + if (ffReadFileData(drmDir.chars, ARRAY_SIZE(modes), modes) >= 3) { + // This is actually preferred resolution + sscanf(modes, "%ux%u", &width, &height); + ffStrbufAppendS(&name, plainName); + } + + uint8_t edidData[1024]; + ssize_t edidLength = ffReadFileData(drmDir.chars, ARRAY_SIZE(edidData), edidData); + if (edidLength > 0 && ffEdidIsValid(edidData, (uint32_t) edidLength)) { ffEdidGetName(edidData, &name); - ffEdidGetPreferredResolutionAndRefreshRate(edidData, &width, &height, &refreshRate); + ffEdidGetPreferredResolutionAndRefreshRate(edidData, &preferredWidth, &preferredHeight, &preferredRefreshRate); ffEdidGetPhysicalSize(edidData, &physicalWidth, &physicalHeight); + } else { + edidLength = 0; } FFDisplayResult* item = ffdsAppendDisplay( result, width, height, - refreshRate, - 0, - 0, 0, 0, + preferredWidth, + preferredHeight, + preferredRefreshRate, 0, &name, ffdsGetDisplayType(plainName), @@ -95,7 +98,8 @@ static const char* drmParseSysfs(FFDisplayServerResult* result) { "sysfs-drm"); if (item && edidLength) { item->hdrStatus = ffEdidGetHdrCompatible(edidData, (uint32_t) edidLength) ? FF_DISPLAY_HDR_STATUS_SUPPORTED : FF_DISPLAY_HDR_STATUS_UNSUPPORTED; - ffEdidGetSerialAndManufactureDate(edidData, &item->serial, &item->manufactureYear, &item->manufactureWeek); + ffEdidGetManufactureDate(edidData, &item->manufactureYear, &item->manufactureWeek); + ffEdidGetSerial(edidData, &item->serial); } ffStrbufSubstrBefore(&drmDir, drmDirLength); @@ -105,13 +109,18 @@ static const char* drmParseSysfs(FFDisplayServerResult* result) { } #endif -#ifdef FF_HAVE_DRM - - #include "common/library.h" +#if FF_HAVE_DRM || __has_include() - #include - #include #include + #include + #if FF_HAVE_DRM + #include + #include + #else + #define FF_HAVE_DRM 1 + #include + #include + #endif // https://gitlab.freedesktop.org/mesa/drm/-/blob/main/xf86drmMode.c#L1785 // It's not supported on Ubuntu 20.04 @@ -207,221 +216,226 @@ FF_A_UNUSED static const char* drmGetEdidByConnId(uint32_t connId, uint8_t* edid } static const char* drmConnectLibdrm(FFDisplayServerResult* result) { - FF_LIBRARY_LOAD_MESSAGE(libdrm, "libdrm" FF_LIBRARY_EXTENSION, 2) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmGetDevices) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeGetResources) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeGetConnectorCurrent) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeGetCrtc) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeGetEncoder) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeGetFB) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeGetProperty) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeGetPropertyBlob) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeFreeResources) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeFreeCrtc) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeFreeConnector) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeFreeEncoder) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeFreeFB) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeFreeProperty) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeFreePropertyBlob) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmFreeDevices) - - drmDevice* devices[64]; - int nDevices = ffdrmGetDevices(devices, ARRAY_SIZE(devices)); - if (nDevices <= 0) { - return "drmGetDevices() failed"; + FF_AUTO_CLOSE_DIR DIR* dirp = opendir("/dev/dri/"); + if (dirp == NULL) { + return "opendir(/dev/dri/) failed"; } + int drifd = dirfd(dirp); - FF_STRBUF_AUTO_DESTROY name = ffStrbufCreate(); + int nSuccess = 0; - for (int iDev = 0; iDev < nDevices; ++iDev) { - drmDevice* dev = devices[iDev]; - - if (!(dev->available_nodes & (1 << DRM_NODE_PRIMARY))) { + struct dirent* entry; + while ((entry = readdir(dirp)) != NULL) { + if (entry->d_name[0] == '.' || !ffStrStartsWith(entry->d_name, "card")) { continue; } - const char* path = dev->nodes[DRM_NODE_PRIMARY]; - #if __linux__ - ffStrbufSetF(&name, "/sys/class/drm/%s/device/power/runtime_status", strrchr(path, '/') + 1); + char powerStatusBuf[512]; + snprintf(powerStatusBuf, ARRAY_SIZE(powerStatusBuf), "/sys/class/drm/%s/device/power/runtime_status", entry->d_name); char buffer[8] = ""; - if (ffReadFileData(name.chars, strlen("suspend"), buffer) > 0 && ffStrStartsWith(buffer, "suspend")) { + if (ffReadFileData(powerStatusBuf, strlen("suspend"), buffer) > 0 && ffStrStartsWith(buffer, "suspend")) { continue; } #endif - FF_AUTO_CLOSE_FD int primaryFd = open(path, O_RDWR | O_CLOEXEC); + FF_AUTO_CLOSE_FD int primaryFd = openat(drifd, entry->d_name, O_RDWR | O_CLOEXEC); if (primaryFd < 0) { continue; } - drmModeRes* res = ffdrmModeGetResources(primaryFd); - if (!res) { + struct drm_mode_card_res res_ = {}; + if (ioctl(primaryFd, DRM_IOCTL_MODE_GETRESOURCES, &res_) < 0 || res_.count_connectors <= 0) { + continue; + } + + FF_AUTO_FREE uint32_t* connectors = malloc(res_.count_connectors * sizeof(*connectors)); + struct drm_mode_card_res res = { + .count_connectors = res_.count_connectors, + .connector_id_ptr = (uintptr_t) connectors, + }; + + if (ioctl(primaryFd, DRM_IOCTL_MODE_GETRESOURCES, &res) < 0) { continue; } - for (int iConn = 0; iConn < res->count_connectors; ++iConn) { - drmModeConnector* conn = ffdrmModeGetConnectorCurrent(primaryFd, res->connectors[iConn]); - if (!conn) { + ++nSuccess; + + for (uint32_t iConn = 0; iConn < res.count_connectors; ++iConn) { + struct drm_mode_get_connector conn = { + .connector_id = connectors[iConn] + }; + if (ioctl(primaryFd, DRM_IOCTL_MODE_GETCONNECTOR, &conn) < 0) { continue; } - if (conn->connection != DRM_MODE_DISCONNECTED) { - drmModeEncoder* encoder = ffdrmModeGetEncoder(primaryFd, conn->encoder_id); - uint32_t width = 0, height = 0, refreshRate = 0; - uint8_t bitDepth = 0; - - if (encoder) { - drmModeCrtc* crtc = ffdrmModeGetCrtc(primaryFd, encoder->crtc_id); - if (crtc) { - width = crtc->mode.hdisplay; - height = crtc->mode.vdisplay; - refreshRate = crtc->mode.vrefresh; - if (refreshRate == 0) { - // There are weird cases that we can't get the refresh rate from the CRTC but from the modes - for (int iMode = 0; iMode < conn->count_modes; ++iMode) { - drmModeModeInfo* mode = &conn->modes[iMode]; - if (mode->clock == crtc->mode.clock && mode->htotal == crtc->mode.htotal) { - refreshRate = mode->vrefresh; - break; - } - } - } + if (conn.connection == 2 /* connector_status_disconnected */) { + continue; + } - drmModeFBPtr fb = ffdrmModeGetFB(primaryFd, crtc->buffer_id); - if (fb) { - bitDepth = (uint8_t) (fb->depth / 3); - ffdrmModeFreeFB(fb); + uint32_t width = 0, height = 0, refreshRate = 0; + uint8_t bitDepth = 0; + + if (conn.encoder_id > 0) { + struct drm_mode_get_encoder enc = { + .encoder_id = conn.encoder_id + }; + if (ioctl(primaryFd, DRM_IOCTL_MODE_GETENCODER, &enc) >= 0 && enc.crtc_id > 0) { + struct drm_mode_crtc crtc = { + .crtc_id = enc.crtc_id, + }; + if (ioctl(primaryFd, DRM_IOCTL_MODE_GETCRTC, &crtc) >= 0) { + width = crtc.mode.hdisplay; + height = crtc.mode.vdisplay; + refreshRate = crtc.mode.vrefresh; + + if (crtc.fb_id > 0) { + struct drm_mode_fb_cmd fb = { + .fb_id = crtc.fb_id, + }; + if (ioctl(primaryFd, DRM_IOCTL_MODE_GETFB, &fb) >= 0) { + bitDepth = (uint8_t) (fb.depth / 3); + } } - - ffdrmModeFreeCrtc(crtc); } - - ffdrmModeFreeEncoder(encoder); } + } - uint32_t preferredWidth = 0, preferredHeight = 0, preferredRefreshRate = 0; - - for (int iMode = 0; iMode < conn->count_modes; ++iMode) { - drmModeModeInfo* mode = &conn->modes[iMode]; - - if (mode->type & DRM_MODE_TYPE_PREFERRED) { - preferredWidth = mode->hdisplay; - preferredHeight = mode->vdisplay; - preferredRefreshRate = mode->vrefresh; - break; + uint32_t preferredWidth = 0, preferredHeight = 0, preferredRefreshRate = 0; + if (conn.count_modes > 0) { + FF_AUTO_FREE struct drm_mode_modeinfo* modes = malloc(conn.count_modes * sizeof(*modes)); + struct drm_mode_get_connector connModes = { + .connector_id = connectors[iConn], + .modes_ptr = (uintptr_t) modes, + .count_modes = conn.count_modes + }; + if (ioctl(primaryFd, DRM_IOCTL_MODE_GETCONNECTOR, &connModes) >= 0) { + for (uint32_t iMode = 0; iMode < connModes.count_modes; ++iMode) { + if (modes[iMode].type & DRM_MODE_TYPE_PREFERRED) { + preferredWidth = modes[iMode].hdisplay; + preferredHeight = modes[iMode].vdisplay; + preferredRefreshRate = modes[iMode].vrefresh; + break; + } } } + } - // NVIDIA DRM driver seems incomplete and conn->encoder_id == 0 - // Assume preferred resolution is used as what we do in drmParseSys - if (width == 0 || height == 0) { - width = preferredWidth; - height = preferredHeight; - refreshRate = preferredRefreshRate; - } - - ffStrbufClear(&name); - uint16_t myear = 0, mweak = 0; - uint32_t serial = 0; - FFDisplayHdrStatus hdrStatus = FF_DISPLAY_HDR_STATUS_UNKNOWN; - - for (int iProp = 0; iProp < conn->count_props; ++iProp) { - drmModePropertyRes* prop = ffdrmModeGetProperty(primaryFd, conn->props[iProp]); - if (!prop) { - continue; - } - - uint32_t type = prop->flags & (DRM_MODE_PROP_LEGACY_TYPE | DRM_MODE_PROP_EXTENDED_TYPE); - if (type == DRM_MODE_PROP_BLOB && ffStrEquals(prop->name, "EDID")) { - drmModePropertyBlobPtr blob = NULL; + if (width == 0 || height == 0) { + width = preferredWidth; + height = preferredHeight; + refreshRate = preferredRefreshRate; + } - if (prop->count_blobs > 0 && prop->blob_ids != NULL) { - blob = ffdrmModeGetPropertyBlob(primaryFd, prop->blob_ids[0]); - } else { - blob = ffdrmModeGetPropertyBlob(primaryFd, (uint32_t) conn->prop_values[iProp]); + FF_STRBUF_AUTO_DESTROY name = ffStrbufCreate(); + uint16_t myear = 0, mweak = 0; + FF_STRBUF_AUTO_DESTROY serial = ffStrbufCreate(); + FFDisplayHdrStatus hdrStatus = FF_DISPLAY_HDR_STATUS_UNKNOWN; + + uint32_t* props = malloc(conn.count_props * sizeof(uint32_t)); + uint64_t* propValues = malloc(conn.count_props * sizeof(uint64_t)); + if (props && propValues && conn.count_props > 0) { + struct drm_mode_get_connector connProps = { + .connector_id = connectors[iConn], + .props_ptr = (uintptr_t) props, + .prop_values_ptr = (uintptr_t) propValues, + .count_props = conn.count_props, + }; + if (ioctl(primaryFd, DRM_IOCTL_MODE_GETCONNECTOR, &connProps) >= 0) { + for (uint32_t iProp = 0; iProp < connProps.count_props; ++iProp) { + struct drm_mode_get_property prop = { + .prop_id = props[iProp], + }; + if (ioctl(primaryFd, DRM_IOCTL_MODE_GETPROPERTY, &prop) < 0) { + continue; } - if (blob) { - if (blob->length >= 128) { - ffEdidGetName(blob->data, &name); - hdrStatus = ffEdidGetHdrCompatible(blob->data, blob->length) ? FF_DISPLAY_HDR_STATUS_SUPPORTED : FF_DISPLAY_HDR_STATUS_UNSUPPORTED; - ffEdidGetSerialAndManufactureDate(blob->data, &serial, &myear, &mweak); + uint32_t type = prop.flags & (DRM_MODE_PROP_LEGACY_TYPE | DRM_MODE_PROP_EXTENDED_TYPE); + if (type == DRM_MODE_PROP_BLOB && ffStrEquals(prop.name, "EDID")) { + struct drm_mode_get_blob blob_ = { + .blob_id = (uint32_t) propValues[iProp] + }; + if (ioctl(primaryFd, DRM_IOCTL_MODE_GETPROPBLOB, &blob_) >= 0 && blob_.length > 0) { + FF_AUTO_FREE void* blobData = malloc(blob_.length); + struct drm_mode_get_blob blob = { + .blob_id = blob_.blob_id, + .length = blob_.length, + .data = (uintptr_t) blobData + }; + if (ioctl(primaryFd, DRM_IOCTL_MODE_GETPROPBLOB, &blob) >= 0 && ffEdidIsValid(blobData, blob.length)) { + ffEdidGetName(blobData, &name); + hdrStatus = ffEdidGetHdrCompatible(blobData, blob.length) ? FF_DISPLAY_HDR_STATUS_SUPPORTED : FF_DISPLAY_HDR_STATUS_UNSUPPORTED; + ffEdidGetManufactureDate(blobData, &myear, &mweak); + ffEdidGetSerial(blobData, &serial); + } } - ffdrmModeFreePropertyBlob(blob); + break; } - break; } - ffdrmModeFreeProperty(prop); } + } #if __linux__ - if (name.length == 0) { - uint8_t edidData[512]; - ssize_t edidLength = 0; - drmGetEdidByConnId(conn->connector_id, edidData, &edidLength); - if (edidLength > 0 && edidLength % 128 == 0) { - ffEdidGetName(edidData, &name); - hdrStatus = ffEdidGetHdrCompatible(edidData, (uint32_t) edidLength) ? FF_DISPLAY_HDR_STATUS_SUPPORTED : FF_DISPLAY_HDR_STATUS_UNSUPPORTED; - ffEdidGetSerialAndManufactureDate(edidData, &serial, &myear, &mweak); - } + if (name.length == 0) { + uint8_t edidData[512]; + ssize_t edidLength = 0; + drmGetEdidByConnId(conn.connector_id, edidData, &edidLength); + if (edidLength > 0 && ffEdidIsValid(edidData, (uint32_t) edidLength)) { + ffEdidGetName(edidData, &name); + hdrStatus = ffEdidGetHdrCompatible(edidData, (uint32_t) edidLength) ? FF_DISPLAY_HDR_STATUS_SUPPORTED : FF_DISPLAY_HDR_STATUS_UNSUPPORTED; + ffEdidGetManufactureDate(edidData, &myear, &mweak); + ffEdidGetSerial(edidData, &serial); } + } #endif - if (name.length == 0) { - const char* connectorTypeName = drmType2Name(conn->connector_type); - if (connectorTypeName == NULL) { - connectorTypeName = "Unknown"; - } - ffStrbufSetF(&name, "%s-%d", connectorTypeName, iConn + 1); - } - - FFDisplayResult* item = ffdsAppendDisplay(result, - width, - height, - refreshRate, - 0, - preferredWidth, - preferredHeight, - preferredRefreshRate, - 0, - &name, - conn->connector_type == DRM_MODE_CONNECTOR_eDP || conn->connector_type == DRM_MODE_CONNECTOR_LVDS - ? FF_DISPLAY_TYPE_BUILTIN - : conn->connector_type == DRM_MODE_CONNECTOR_HDMIA || conn->connector_type == DRM_MODE_CONNECTOR_HDMIB || conn->connector_type == DRM_MODE_CONNECTOR_DisplayPort - ? FF_DISPLAY_TYPE_EXTERNAL - : FF_DISPLAY_TYPE_UNKNOWN, - false, - conn->connector_id, - conn->mmWidth, - conn->mmHeight, - "libdrm"); - - if (item) { - item->hdrStatus = hdrStatus; - item->serial = serial; - item->manufactureYear = myear; - item->manufactureWeek = mweak; - item->bitDepth = bitDepth; + if (name.length == 0) { + const char* connectorTypeName = drmType2Name(conn.connector_type); + if (connectorTypeName == NULL) { + connectorTypeName = "Unknown"; } + ffStrbufSetF(&name, "%s-%d", connectorTypeName, iConn + 1); } - ffdrmModeFreeConnector(conn); + FFDisplayResult* item = ffdsAppendDisplay(result, + width, + height, + refreshRate, + 0, + preferredWidth, + preferredHeight, + preferredRefreshRate, + 0, + &name, + conn.connector_type == DRM_MODE_CONNECTOR_eDP || conn.connector_type == DRM_MODE_CONNECTOR_LVDS + ? FF_DISPLAY_TYPE_BUILTIN + : conn.connector_type == DRM_MODE_CONNECTOR_HDMIA || conn.connector_type == DRM_MODE_CONNECTOR_HDMIB || conn.connector_type == DRM_MODE_CONNECTOR_DisplayPort + ? FF_DISPLAY_TYPE_EXTERNAL + : FF_DISPLAY_TYPE_UNKNOWN, + false, + conn.connector_id, + conn.mm_width, + conn.mm_height, + "libdrm"); + + if (item) { + item->hdrStatus = hdrStatus; + ffStrbufInitMove(&item->serial, &serial); + item->manufactureYear = myear; + item->manufactureWeek = mweak; + item->bitDepth = bitDepth; + } } - - ffdrmModeFreeResources(res); } - ffdrmFreeDevices(devices, nDevices); - - return NULL; + return nSuccess > 0 ? NULL : "No connectors found using libdrm"; } #endif const char* ffdsConnectDrm(FF_A_UNUSED FFDisplayServerResult* result) { -#ifdef FF_HAVE_DRM +#if FF_HAVE_DRM if (instance.config.general.dsForceDrm != FF_DS_FORCE_DRM_TYPE_SYSFS_ONLY) { if (drmConnectLibdrm(result) == NULL) { return NULL; diff --git a/src/detection/displayserver/linux/wayland/global-output.c b/src/detection/displayserver/linux/wayland/global-output.c index 51fb425610..e15199218a 100644 --- a/src/detection/displayserver/linux/wayland/global-output.c +++ b/src/detection/displayserver/linux/wayland/global-output.c @@ -3,6 +3,7 @@ #include "wayland.h" #include "common/strutil.h" #include "xdg-output-unstable-v1-client-protocol.h" + #include "wp-color-management-v1-client-protocol.h" static void waylandOutputModeListener(void* data, FF_A_UNUSED struct wl_output* output, uint32_t flags, int32_t width, int32_t height, int32_t refreshRate) { WaylandDisplay* display = data; @@ -70,10 +71,36 @@ static struct zxdg_output_v1_listener zxdgOutputListener = { .description = (void*) ffWaylandOutputDescriptionListener, }; +static void handleWpTfNamed(void *data, FF_A_UNUSED struct wp_image_description_info_v1* wp_image_description_info_v1, uint32_t tf) { + // KDE reports `gamma 2.2` even in HDR mode, but it should be handled in KDE specific path + WaylandDisplay* display = data; + switch (tf) { + case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ: + case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_HLG: + display->hdrInfoAvailable = true; + display->hdrEnabled = true; + break; + } +} + +static const struct wp_image_description_info_v1_listener wpImageDescInfoListener = { + .done = (void*) stubListener, + .icc_file = (void*) stubListener, + .primaries = (void*) stubListener, + .primaries_named = (void*) stubListener, + .tf_power = (void*) stubListener, + .tf_named = (void*) handleWpTfNamed, + .luminances = (void*) stubListener, + .target_primaries = (void*) stubListener, + .target_luminance = (void*) stubListener, + .target_max_cll = (void*) stubListener, + .target_max_fall = (void*) stubListener, +}; + const char* ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version) { - const char* api = "wayland-global"; + const char* api = "wayland-base"; uint32_t bindVersion = min(version, WL_OUTPUT_DESCRIPTION_SINCE_VERSION); - struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, wldata->ffwl_output_interface, bindVersion, name, wldata->ffwl_output_interface->name, bindVersion, NULL); + struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &wl_output_interface, bindVersion, name, wl_output_interface.name, bindVersion, NULL); if (output == NULL) { return "Failed to create wl_output"; } @@ -104,7 +131,28 @@ const char* ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry* wldata->ffwl_proxy_add_listener(zxdgOutput, (void (**)(void)) &zxdgOutputListener, &display); wldata->ffwl_display_roundtrip(wldata->display); wldata->ffwl_proxy_destroy(zxdgOutput); - api = "wayland-global-zxdg"; + api = "wayland-zxdg"; + } + } + + if (wldata->wpColorManager) { + uint32_t bindVersion = min(version, WP_COLOR_MANAGER_V1_GET_OUTPUT_SINCE_VERSION); + struct wl_proxy* wpColorOutput = wldata->ffwl_proxy_marshal_constructor_versioned(wldata->wpColorManager, WP_COLOR_MANAGER_V1_GET_OUTPUT, &wp_color_management_output_v1_interface, bindVersion, NULL, output); + + if (wpColorOutput) { + struct wl_proxy* wpImageDesc = wldata->ffwl_proxy_marshal_constructor_versioned(wpColorOutput, WP_COLOR_MANAGEMENT_OUTPUT_V1_GET_IMAGE_DESCRIPTION, &wp_image_description_v1_interface, bindVersion, NULL); + if (wpImageDesc) { + struct wl_proxy* wpImageDescInfo = wldata->ffwl_proxy_marshal_constructor_versioned(wpImageDesc, WP_IMAGE_DESCRIPTION_V1_GET_INFORMATION, &wp_image_description_info_v1_interface, bindVersion, NULL); + if (wpImageDescInfo) { + wldata->ffwl_proxy_add_listener(wpImageDescInfo, (void (**)(void)) &wpImageDescInfoListener, &display); + wldata->ffwl_display_roundtrip(wldata->display); + wldata->ffwl_proxy_destroy(wpImageDescInfo); + } + wldata->ffwl_proxy_destroy(wpImageDesc); + } + wldata->ffwl_proxy_destroy(wpColorOutput); + wldata->ffwl_display_roundtrip(wldata->display); + api = api[strlen("wayland-")] == 'z' ? "wayland-zxdg+wpcolor" : "wayland-wpcolor"; } } @@ -138,7 +186,9 @@ const char* ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry* (uint32_t) display.physicalHeight, api); if (item) { - if (display.hdrSupported) { + if (display.hdrEnabled) { + item->hdrStatus = FF_DISPLAY_HDR_STATUS_ENABLED; + } else if (display.hdrSupported) { item->hdrStatus = FF_DISPLAY_HDR_STATUS_SUPPORTED; } else if (display.hdrInfoAvailable) { item->hdrStatus = FF_DISPLAY_HDR_STATUS_UNSUPPORTED; @@ -148,7 +198,7 @@ const char* ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry* item->manufactureYear = display.myear; item->manufactureWeek = display.mweek; - item->serial = display.serial; + ffStrbufInitMove(&item->serial, &display.serial); } ffStrbufDestroy(&display.description); @@ -170,4 +220,16 @@ const char* ffWaylandHandleZxdgOutput(WaylandData* wldata, struct wl_registry* r return NULL; } +const char* ffWaylandHandleWpColor(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version) { + uint32_t bindVersion = min(version, WP_COLOR_MANAGER_V1_GET_OUTPUT_SINCE_VERSION); + struct wl_proxy* manager = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &wp_color_manager_v1_interface, bindVersion, name, wp_color_manager_v1_interface.name, bindVersion, NULL); + if (manager == NULL) { + return "Failed to create wp_color_manager_v1"; + } + + wldata->wpColorManager = manager; + + return NULL; +} + #endif diff --git a/src/detection/displayserver/linux/wayland/kde-output-order-v1-client-protocol.h b/src/detection/displayserver/linux/wayland/kde-output-order-v1-client-protocol.h deleted file mode 100644 index b9928c3fec..0000000000 --- a/src/detection/displayserver/linux/wayland/kde-output-order-v1-client-protocol.h +++ /dev/null @@ -1,134 +0,0 @@ -/* Generated by wayland-scanner 1.22.0 */ - -#ifndef KDE_OUTPUT_ORDER_V1_CLIENT_PROTOCOL_H -#define KDE_OUTPUT_ORDER_V1_CLIENT_PROTOCOL_H - -#include -#include -#include "wayland-client.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @page page_kde_output_order_v1 The kde_output_order_v1 protocol - * @section page_ifaces_kde_output_order_v1 Interfaces - * - @subpage page_iface_kde_output_order_v1 - announce order of outputs - * @section page_copyright_kde_output_order_v1 Copyright - *
- *
- * SPDX-FileCopyrightText: 2022 Xaver Hugl 
- *
- * SPDX-License-Identifier: MIT-CMU
- * 
- */ -struct kde_output_order_v1; - -#ifndef KDE_OUTPUT_ORDER_V1_INTERFACE - #define KDE_OUTPUT_ORDER_V1_INTERFACE -/** - * @page page_iface_kde_output_order_v1 kde_output_order_v1 - * @section page_iface_kde_output_order_v1_desc Description - * - * Announce the order in which desktop environment components should be placed on outputs. - * The compositor will send the list of outputs when the global is bound and whenever there is a change. - * @section page_iface_kde_output_order_v1_api API - * See @ref iface_kde_output_order_v1. - */ -/** - * @defgroup iface_kde_output_order_v1 The kde_output_order_v1 interface - * - * Announce the order in which desktop environment components should be placed on outputs. - * The compositor will send the list of outputs when the global is bound and whenever there is a change. - */ -extern const struct wl_interface kde_output_order_v1_interface; -#endif - -/** - * @ingroup iface_kde_output_order_v1 - * @struct kde_output_order_v1_listener - */ -struct kde_output_order_v1_listener { - /** - * output name - * - * Specifies the output identified by their wl_output.name. - * @param output_name the name of the output - */ - void (*output)(void* data, - struct kde_output_order_v1* kde_output_order_v1, - const char* output_name); - /** - * done - * - * Specifies that the output list is complete. On the next output - * event, a new list begins. - */ - void (*done)(void* data, - struct kde_output_order_v1* kde_output_order_v1); -}; - -/** - * @ingroup iface_kde_output_order_v1 - */ -static inline int -kde_output_order_v1_add_listener(struct kde_output_order_v1* kde_output_order_v1, - const struct kde_output_order_v1_listener* listener, - void* data) { - return wl_proxy_add_listener((struct wl_proxy*) kde_output_order_v1, - (void (**)(void)) listener, - data); -} - -#define KDE_OUTPUT_ORDER_V1_DESTROY 0 - -/** - * @ingroup iface_kde_output_order_v1 - */ -#define KDE_OUTPUT_ORDER_V1_OUTPUT_SINCE_VERSION 1 -/** - * @ingroup iface_kde_output_order_v1 - */ -#define KDE_OUTPUT_ORDER_V1_DONE_SINCE_VERSION 1 - -/** - * @ingroup iface_kde_output_order_v1 - */ -#define KDE_OUTPUT_ORDER_V1_DESTROY_SINCE_VERSION 1 - -// /** @ingroup iface_kde_output_order_v1 */ -// static inline void -// kde_output_order_v1_set_user_data(struct kde_output_order_v1 *kde_output_order_v1, void *user_data) -// { -// wl_proxy_set_user_data((struct wl_proxy *) kde_output_order_v1, user_data); -// } - -// /** @ingroup iface_kde_output_order_v1 */ -// static inline void * -// kde_output_order_v1_get_user_data(struct kde_output_order_v1 *kde_output_order_v1) -// { -// return wl_proxy_get_user_data((struct wl_proxy *) kde_output_order_v1); -// } - -// static inline uint32_t -// kde_output_order_v1_get_version(struct kde_output_order_v1 *kde_output_order_v1) -// { -// return wl_proxy_get_version((struct wl_proxy *) kde_output_order_v1); -// } - -// /** -// * @ingroup iface_kde_output_order_v1 -// */ -// static inline void -// kde_output_order_v1_destroy(struct kde_output_order_v1 *kde_output_order_v1) -// { -// wl_proxy_marshal_flags((struct wl_proxy *) kde_output_order_v1, -// KDE_OUTPUT_ORDER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) kde_output_order_v1), WL_MARSHAL_FLAG_DESTROY); -// } - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/detection/displayserver/linux/wayland/kde-output-order-v1-protocol.c b/src/detection/displayserver/linux/wayland/kde-output-order-v1-protocol.c deleted file mode 100644 index 00db32af5d..0000000000 --- a/src/detection/displayserver/linux/wayland/kde-output-order-v1-protocol.c +++ /dev/null @@ -1,37 +0,0 @@ -#ifdef FF_HAVE_WAYLAND - -/* Generated by wayland-scanner 1.22.0 */ - -/* - * SPDX-FileCopyrightText: 2022 Xaver Hugl - * - * SPDX-License-Identifier: MIT-CMU - */ - - #include - #include - #include "wayland-util.h" - -static const struct wl_interface* kde_output_order_v1_types[] = { - NULL, -}; - -static const struct wl_message kde_output_order_v1_requests[] = { - { "destroy", "", kde_output_order_v1_types + 0 }, -}; - -static const struct wl_message kde_output_order_v1_events[] = { - { "output", "s", kde_output_order_v1_types + 0 }, - { "done", "", kde_output_order_v1_types + 0 }, -}; - -WL_EXPORT const struct wl_interface kde_output_order_v1_interface = { - "kde_output_order_v1", - 1, - 1, - kde_output_order_v1_requests, - 2, - kde_output_order_v1_events, -}; - -#endif diff --git a/src/detection/displayserver/linux/wayland/kde-output.c b/src/detection/displayserver/linux/wayland/kde-output.c index 90d5770cde..73f9ac5aff 100644 --- a/src/detection/displayserver/linux/wayland/kde-output.c +++ b/src/detection/displayserver/linux/wayland/kde-output.c @@ -2,7 +2,6 @@ #include "wayland.h" #include "kde-output-device-v2-client-protocol.h" - #include "kde-output-order-v1-client-protocol.h" #include "common/edidHelper.h" #include "common/base64.h" @@ -96,7 +95,8 @@ static void waylandKdeEdidListener(void* data, FF_A_UNUSED struct kde_output_dev } ffEdidGetName((const uint8_t*) edid.chars, &wldata->edidName); wldata->hdrSupported = ffEdidGetHdrCompatible((const uint8_t*) edid.chars, edid.length); - ffEdidGetSerialAndManufactureDate((const uint8_t*) edid.chars, &wldata->serial, &wldata->myear, &wldata->mweek); + ffEdidGetManufactureDate((const uint8_t*) edid.chars, &wldata->myear, &wldata->mweek); + ffEdidGetSerial((const uint8_t*) edid.chars, &wldata->serial); wldata->hdrInfoAvailable = true; } @@ -142,6 +142,11 @@ static void waylandKdeMaxBitsPerColorListener(void* data, FF_A_UNUSED struct kde display->bitDepth = (uint8_t) max_bpc; } +static void waylandKdePriorityListener(void* data, FF_A_UNUSED struct kde_output_device_v2* kde_output_device_v2, uint32_t priority) { + WaylandDisplay* display = data; + display->primary = priority == 1; +} + static struct kde_output_device_v2_listener outputListener = { .geometry = waylandKdeGeometryListener, .current_mode = waylandKdeCurrentModeListener, @@ -176,15 +181,16 @@ static struct kde_output_device_v2_listener outputListener = { .max_bits_per_color_range = (void*) stubListener, .automatic_max_bits_per_color_limit = (void*) stubListener, .edr_policy = (void*) stubListener, + .sharpness = (void*) stubListener, + .priority = waylandKdePriorityListener, + .auto_brightness = (void*) stubListener, + .removed = (void*) stubListener, + .hdr_icc_profile_path = (void*) stubListener, + .hdr_color_profile_source = (void*) stubListener, + .abm_level = (void*) stubListener, }; -const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version) { - uint32_t bindVersion = min(version, KDE_OUTPUT_DEVICE_V2_MAX_BITS_PER_COLOR_SINCE_VERSION); - struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &kde_output_device_v2_interface, bindVersion, name, kde_output_device_v2_interface.name, bindVersion, NULL); - if (output == NULL) { - return "Failed to create kde_output_device_v2"; - } - +static const char* waylandKdeHandleOutput(WaylandData* wldata, struct wl_proxy* output) { FF_LIST_AUTO_DESTROY modes = ffListCreate(); WaylandDisplay display = { .parent = wldata, @@ -236,7 +242,7 @@ const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* re ? &display.edidName : &display.name, display.type, - false, + display.primary, display.id, (uint32_t) display.physicalWidth, (uint32_t) display.physicalHeight, @@ -254,7 +260,7 @@ const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* re item->manufactureYear = display.myear; item->manufactureWeek = display.mweek; - item->serial = display.serial; + ffStrbufInitMove(&item->serial, &display.serial); item->bitDepth = display.bitDepth; } @@ -265,35 +271,42 @@ const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* re return NULL; } -static void waylandKdeOutputOrderListener(void* data, FF_A_UNUSED struct kde_output_order_v1* _, const char* output_name) { - uint64_t* id = (uint64_t*) data; - if (*id == 0) { - *id = ffWaylandGenerateIdFromName(output_name); +const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version) { + // TODO: remove this in future versions + uint32_t bindVersion = min(version, KDE_OUTPUT_DEVICE_V2_PRIORITY_SINCE_VERSION); + struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &kde_output_device_v2_interface, bindVersion, name, kde_output_device_v2_interface.name, bindVersion, NULL); + if (output == NULL) { + return "Failed to create kde_output_device_v2"; } + + return waylandKdeHandleOutput(wldata, output); } -static const struct kde_output_order_v1_listener orderListener = { - .output = waylandKdeOutputOrderListener, - .done = (void*) stubListener, +static void waylandKdeOutputListener(void* data, FF_A_UNUSED struct kde_output_device_registry_v2* kde_output_device_registry_v2, struct kde_output_device_v2* output) { + waylandKdeHandleOutput((WaylandData*) data, (struct wl_proxy*) output); +} + +static struct kde_output_device_registry_v2_listener registryListener = { + .output = waylandKdeOutputListener, + .finished = (void*) stubListener, }; -const char* ffWaylandHandleKdeOutputOrder(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version) { - uint32_t bindVersion = min(version, KDE_OUTPUT_ORDER_V1_OUTPUT_SINCE_VERSION); - struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &kde_output_order_v1_interface, bindVersion, name, kde_output_order_v1_interface.name, bindVersion, NULL); - if (output == NULL) { - return "Failed to create kde_output_order_v1"; +const char* ffWaylandHandleKdeOutputRegistry(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version) { + uint32_t bindVersion = min(version, KDE_OUTPUT_DEVICE_REGISTRY_V2_OUTPUT_SINCE_VERSION); + struct wl_proxy* outputRegistry = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &kde_output_device_registry_v2_interface, bindVersion, name, kde_output_device_registry_v2_interface.name, bindVersion, NULL); + if (outputRegistry == NULL) { + return "Failed to create kde_output_device_registry_v2"; } - - if (wldata->ffwl_proxy_add_listener(output, (void (**)(void)) &orderListener, &wldata->primaryDisplayId) < 0) { - wldata->ffwl_proxy_destroy(output); - return "Failed to add listener to kde_output_order_v1"; + if (wldata->ffwl_proxy_add_listener(outputRegistry, (void (**)(void)) ®istryListener, wldata) < 0) { + wldata->ffwl_proxy_destroy(outputRegistry); + return "Failed to add listener to kde_output_device_registry_v2"; } if (wldata->ffwl_display_roundtrip(wldata->display) < 0) { - wldata->ffwl_proxy_destroy(output); - return "Failed to roundtrip kde_output_order_v1"; + wldata->ffwl_proxy_destroy(outputRegistry); + return "Failed to roundtrip kde_output_device_registry_v2"; } - wldata->ffwl_proxy_destroy(output); + wldata->ffwl_proxy_destroy(outputRegistry); return NULL; } diff --git a/src/detection/displayserver/linux/wayland/wayland.c b/src/detection/displayserver/linux/wayland/wayland.c index 064c239070..647aa067f7 100644 --- a/src/detection/displayserver/linux/wayland/wayland.c +++ b/src/detection/displayserver/linux/wayland/wayland.c @@ -13,10 +13,9 @@ #include "common/properties.h" #include "wayland.h" - #include "wlr-output-management-unstable-v1-client-protocol.h" #include "kde-output-device-v2-client-protocol.h" - #include "kde-output-order-v1-client-protocol.h" #include "xdg-output-unstable-v1-client-protocol.h" + #include "wp-color-management-v1-client-protocol.h" #if __FreeBSD__ #include @@ -81,25 +80,25 @@ static bool waylandDetectWM(int fd, FFDisplayServerResult* result) { static void waylandGlobalAddListener(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version) { WaylandData* wldata = data; - if ((wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_NONE || wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_GLOBAL) && ffStrEquals(interface, wldata->ffwl_output_interface->name)) { + if ((wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_NONE || wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_GLOBAL) && ffStrEquals(interface, wl_output_interface.name)) { wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_GLOBAL; if (ffWaylandHandleGlobalOutput(wldata, registry, name, version) != NULL) { wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_NONE; } - } else if ((wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_NONE || wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_ZWLR) && ffStrEquals(interface, zwlr_output_manager_v1_interface.name)) { - wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_ZWLR; - if (ffWaylandHandleZwlrOutput(wldata, registry, name, version) != NULL) { + } else if ((wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_NONE) && ffStrEquals(interface, kde_output_device_registry_v2_interface.name)) { + wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_KDE_REGISTRY; + if (ffWaylandHandleKdeOutputRegistry(wldata, registry, name, version) != NULL) { wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_NONE; } - } else if ((wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_NONE || wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_KDE) && ffStrEquals(interface, kde_output_device_v2_interface.name)) { - wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_KDE; + } else if ((wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_NONE || wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_KDE_DEPRECATED) && ffStrEquals(interface, kde_output_device_v2_interface.name)) { + wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_KDE_DEPRECATED; if (ffWaylandHandleKdeOutput(wldata, registry, name, version) != NULL) { wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_NONE; } - } else if (ffStrEquals(interface, kde_output_order_v1_interface.name)) { - ffWaylandHandleKdeOutputOrder(wldata, registry, name, version); } else if ((wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_GLOBAL || wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_NONE) && ffStrEquals(interface, zxdg_output_manager_v1_interface.name)) { ffWaylandHandleZxdgOutput(wldata, registry, name, version); + } else if ((wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_GLOBAL || wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_NONE) && ffStrEquals(interface, wp_color_manager_v1_interface.name)) { + ffWaylandHandleWpColor(wldata, registry, name, version); } } @@ -128,10 +127,19 @@ static FF_A_UNUSED bool matchDrmConnector(const char* connName, WaylandDisplay* uint8_t edidData[512]; ssize_t edidLength = ffReadFileData(path.chars, ARRAY_SIZE(edidData), edidData); - if (edidLength > 0 && edidLength % 128 == 0) { + if (edidLength > 0 && ffEdidIsValid(edidData, (uint32_t) edidLength)) { ffEdidGetName(edidData, &wldata->edidName); - ffEdidGetHdrCompatible(edidData, (uint32_t) edidLength); - ffEdidGetSerialAndManufactureDate(edidData, &wldata->serial, &wldata->myear, &wldata->mweek); + wldata->hdrSupported = ffEdidGetHdrCompatible(edidData, (uint32_t) edidLength); + ffEdidGetManufactureDate((const uint8_t*) edidData, &wldata->myear, &wldata->mweek); + ffEdidGetSerial((const uint8_t*) edidData, &wldata->serial); + if (wldata->preferredWidth == 0) { + uint32_t preferredWidth = 0, preferredHeight = 0; + double preferredRefreshRate = 0; + ffEdidGetPreferredResolutionAndRefreshRate(edidData, &preferredWidth, &preferredHeight, &preferredRefreshRate); + wldata->preferredWidth = (int32_t) preferredWidth; + wldata->preferredHeight = (int32_t) preferredHeight; + wldata->preferredRefreshRate = (int32_t) (preferredRefreshRate * 1000.); + } wldata->hdrInfoAvailable = true; return true; } @@ -220,7 +228,6 @@ const char* ffdsConnectWayland(FFDisplayServerResult* result) { FF_LIBRARY_LOAD_SYMBOL_MESSAGE(wayland, wl_display_get_fd) FF_LIBRARY_LOAD_SYMBOL_MESSAGE(wayland, wl_proxy_marshal_constructor) FF_LIBRARY_LOAD_SYMBOL_MESSAGE(wayland, wl_display_disconnect) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(wayland, wl_registry_interface) WaylandData data = {}; @@ -228,7 +235,6 @@ const char* ffdsConnectWayland(FFDisplayServerResult* result) { FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(wayland, data, wl_proxy_add_listener) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(wayland, data, wl_proxy_destroy) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(wayland, data, wl_display_roundtrip) - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(wayland, data, wl_output_interface) data.display = ffwl_display_connect(NULL); if (data.display == NULL) { @@ -237,7 +243,7 @@ const char* ffdsConnectWayland(FFDisplayServerResult* result) { waylandDetectWM(ffwl_display_get_fd(data.display), result); - struct wl_proxy* registry = ffwl_proxy_marshal_constructor((struct wl_proxy*) data.display, WL_DISPLAY_GET_REGISTRY, ffwl_registry_interface, NULL); + struct wl_proxy* registry = ffwl_proxy_marshal_constructor((struct wl_proxy*) data.display, WL_DISPLAY_GET_REGISTRY, &wl_registry_interface, NULL); if (registry == NULL) { ffwl_display_disconnect(data.display); return "wl_display_get_registry returned NULL"; @@ -257,10 +263,14 @@ const char* ffdsConnectWayland(FFDisplayServerResult* result) { data.ffwl_proxy_destroy(data.zxdgOutputManager); } + if (data.wpColorManager) { + data.ffwl_proxy_destroy(data.wpColorManager); + } + data.ffwl_proxy_destroy(registry); ffwl_display_disconnect(data.display); - if (data.primaryDisplayId == 0 && result->wmProcessName.length > 0) { + { const char* fileName = ffStrbufEqualS(&result->wmProcessName, "gnome-shell") ? "monitors.xml" : ffStrbufEqualS(&result->wmProcessName, "cinnamon") @@ -307,7 +317,14 @@ const char* ffdsConnectWayland(FFDisplayServerResult* result) { if (end < monitorsXml.length) { ffStrbufSubstrBefore(&monitorsXml, end); const char* name = monitorsXml.chars + start + strlen(""); - data.primaryDisplayId = ffWaylandGenerateIdFromName(name); + uint64_t primaryDisplayId = ffWaylandGenerateIdFromName(name); + + FF_LIST_FOR_EACH (FFDisplayResult, d, data.result->displays) { + if (d->id == primaryDisplayId) { + d->primary = true; + break; + } + } } } } @@ -315,15 +332,6 @@ const char* ffdsConnectWayland(FFDisplayServerResult* result) { } } - if (data.primaryDisplayId) { - FF_LIST_FOR_EACH (FFDisplayResult, d, data.result->displays) { - if (d->id == data.primaryDisplayId) { - d->primary = true; - break; - } - } - } - // We successfully connected to wayland and detected the display. // So we can set set the session type to wayland. // This is used as an indicator that we are running wayland by the x11 backends. diff --git a/src/detection/displayserver/linux/wayland/wayland.h b/src/detection/displayserver/linux/wayland/wayland.h index b103ab934a..e9d4fede83 100644 --- a/src/detection/displayserver/linux/wayland/wayland.h +++ b/src/detection/displayserver/linux/wayland/wayland.h @@ -16,8 +16,8 @@ static inline uint32_t min(uint32_t a, uint32_t b) { typedef enum FF_A_PACKED WaylandProtocolType { FF_WAYLAND_PROTOCOL_TYPE_NONE, FF_WAYLAND_PROTOCOL_TYPE_GLOBAL, - FF_WAYLAND_PROTOCOL_TYPE_ZWLR, - FF_WAYLAND_PROTOCOL_TYPE_KDE, + FF_WAYLAND_PROTOCOL_TYPE_KDE_DEPRECATED, + FF_WAYLAND_PROTOCOL_TYPE_KDE_REGISTRY, } WaylandProtocolType; typedef struct WaylandData { @@ -27,10 +27,9 @@ typedef struct WaylandData { FF_LIBRARY_SYMBOL(wl_proxy_destroy) FF_LIBRARY_SYMBOL(wl_display_roundtrip) struct wl_display* display; - const struct wl_interface* ffwl_output_interface; WaylandProtocolType protocolType; - uint64_t primaryDisplayId; struct wl_proxy* zxdgOutputManager; + struct wl_proxy* wpColorManager; } WaylandData; typedef struct WaylandDisplay { @@ -56,8 +55,9 @@ typedef struct WaylandDisplay { bool hdrEnabled; uint16_t myear; uint16_t mweek; - uint32_t serial; + FFstrbuf serial; uint8_t bitDepth; + bool primary; } WaylandDisplay; inline static void stubListener(void* data, ...) { @@ -81,9 +81,10 @@ void ffWaylandOutputDescriptionListener(void* data, FF_A_UNUSED void* output, co uint32_t ffWaylandHandleRotation(WaylandDisplay* display); const char* ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version); -const char* ffWaylandHandleZwlrOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version); +const char* ffWaylandHandleKdeOutputRegistry(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version); const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version); const char* ffWaylandHandleKdeOutputOrder(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version); const char* ffWaylandHandleZxdgOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version); +const char* ffWaylandHandleWpColor(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version); #endif diff --git a/src/detection/displayserver/linux/wayland/wl-output-protocol.c b/src/detection/displayserver/linux/wayland/wl-output-protocol.c new file mode 100644 index 0000000000..86701209ad --- /dev/null +++ b/src/detection/displayserver/linux/wayland/wl-output-protocol.c @@ -0,0 +1,531 @@ +#ifdef FF_HAVE_WAYLAND + +/* Generated by wayland-scanner 1.24.0 */ + +/* + * Copyright © 2008-2011 Kristian Høgsberg + * Copyright © 2010-2011 Intel Corporation + * Copyright © 2012-2013 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include + +extern const struct wl_interface wl_buffer_interface; +extern const struct wl_interface wl_callback_interface; +extern const struct wl_interface wl_data_device_interface; +extern const struct wl_interface wl_data_offer_interface; +extern const struct wl_interface wl_data_source_interface; +extern const struct wl_interface wl_keyboard_interface; +extern const struct wl_interface wl_output_interface; +extern const struct wl_interface wl_pointer_interface; +extern const struct wl_interface wl_region_interface; +extern const struct wl_interface wl_registry_interface; +extern const struct wl_interface wl_seat_interface; +extern const struct wl_interface wl_shell_surface_interface; +extern const struct wl_interface wl_shm_pool_interface; +extern const struct wl_interface wl_subsurface_interface; +extern const struct wl_interface wl_surface_interface; +extern const struct wl_interface wl_touch_interface; + +static const struct wl_interface *wayland_types[] = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &wl_callback_interface, + &wl_registry_interface, + &wl_surface_interface, + &wl_region_interface, + &wl_buffer_interface, + NULL, + NULL, + NULL, + NULL, + NULL, + &wl_shm_pool_interface, + NULL, + NULL, + &wl_data_source_interface, + &wl_surface_interface, + &wl_surface_interface, + NULL, + &wl_data_source_interface, + NULL, + &wl_data_offer_interface, + NULL, + &wl_surface_interface, + NULL, + NULL, + &wl_data_offer_interface, + &wl_data_offer_interface, + &wl_data_source_interface, + &wl_data_device_interface, + &wl_seat_interface, + &wl_shell_surface_interface, + &wl_surface_interface, + &wl_seat_interface, + NULL, + &wl_seat_interface, + NULL, + NULL, + &wl_surface_interface, + NULL, + NULL, + NULL, + NULL, + NULL, + &wl_output_interface, + &wl_seat_interface, + NULL, + &wl_surface_interface, + NULL, + NULL, + NULL, + &wl_output_interface, + &wl_buffer_interface, + NULL, + NULL, + &wl_callback_interface, + &wl_region_interface, + &wl_region_interface, + &wl_output_interface, + &wl_output_interface, + &wl_pointer_interface, + &wl_keyboard_interface, + &wl_touch_interface, + NULL, + &wl_surface_interface, + NULL, + NULL, + NULL, + &wl_surface_interface, + NULL, + NULL, + NULL, + &wl_surface_interface, + NULL, + &wl_surface_interface, + NULL, + NULL, + &wl_surface_interface, + NULL, + NULL, + &wl_surface_interface, + NULL, + NULL, + NULL, + &wl_subsurface_interface, + &wl_surface_interface, + &wl_surface_interface, + &wl_surface_interface, + &wl_surface_interface, + &wl_registry_interface, +}; + +static const struct wl_message wl_display_requests[] = { + { "sync", "n", wayland_types + 8 }, + { "get_registry", "n", wayland_types + 9 }, +}; + +static const struct wl_message wl_display_events[] = { + { "error", "ous", wayland_types + 0 }, + { "delete_id", "u", wayland_types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_display_interface = { + "wl_display", 1, + 2, wl_display_requests, + 2, wl_display_events, +}; + +static const struct wl_message wl_registry_requests[] = { + { "bind", "usun", wayland_types + 0 }, +}; + +static const struct wl_message wl_registry_events[] = { + { "global", "usu", wayland_types + 0 }, + { "global_remove", "u", wayland_types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_registry_interface = { + "wl_registry", 1, + 1, wl_registry_requests, + 2, wl_registry_events, +}; + +static const struct wl_message wl_callback_events[] = { + { "done", "u", wayland_types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_callback_interface = { + "wl_callback", 1, + 0, NULL, + 1, wl_callback_events, +}; + +static const struct wl_message wl_compositor_requests[] = { + { "create_surface", "n", wayland_types + 10 }, + { "create_region", "n", wayland_types + 11 }, +}; + +WL_EXPORT const struct wl_interface wl_compositor_interface = { + "wl_compositor", 6, + 2, wl_compositor_requests, + 0, NULL, +}; + +static const struct wl_message wl_shm_pool_requests[] = { + { "create_buffer", "niiiiu", wayland_types + 12 }, + { "destroy", "", wayland_types + 0 }, + { "resize", "i", wayland_types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_shm_pool_interface = { + "wl_shm_pool", 2, + 3, wl_shm_pool_requests, + 0, NULL, +}; + +static const struct wl_message wl_shm_requests[] = { + { "create_pool", "nhi", wayland_types + 18 }, + { "release", "2", wayland_types + 0 }, +}; + +static const struct wl_message wl_shm_events[] = { + { "format", "u", wayland_types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_shm_interface = { + "wl_shm", 2, + 2, wl_shm_requests, + 1, wl_shm_events, +}; + +static const struct wl_message wl_buffer_requests[] = { + { "destroy", "", wayland_types + 0 }, +}; + +static const struct wl_message wl_buffer_events[] = { + { "release", "", wayland_types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_buffer_interface = { + "wl_buffer", 1, + 1, wl_buffer_requests, + 1, wl_buffer_events, +}; + +static const struct wl_message wl_data_offer_requests[] = { + { "accept", "u?s", wayland_types + 0 }, + { "receive", "sh", wayland_types + 0 }, + { "destroy", "", wayland_types + 0 }, + { "finish", "3", wayland_types + 0 }, + { "set_actions", "3uu", wayland_types + 0 }, +}; + +static const struct wl_message wl_data_offer_events[] = { + { "offer", "s", wayland_types + 0 }, + { "source_actions", "3u", wayland_types + 0 }, + { "action", "3u", wayland_types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_data_offer_interface = { + "wl_data_offer", 3, + 5, wl_data_offer_requests, + 3, wl_data_offer_events, +}; + +static const struct wl_message wl_data_source_requests[] = { + { "offer", "s", wayland_types + 0 }, + { "destroy", "", wayland_types + 0 }, + { "set_actions", "3u", wayland_types + 0 }, +}; + +static const struct wl_message wl_data_source_events[] = { + { "target", "?s", wayland_types + 0 }, + { "send", "sh", wayland_types + 0 }, + { "cancelled", "", wayland_types + 0 }, + { "dnd_drop_performed", "3", wayland_types + 0 }, + { "dnd_finished", "3", wayland_types + 0 }, + { "action", "3u", wayland_types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_data_source_interface = { + "wl_data_source", 3, + 3, wl_data_source_requests, + 6, wl_data_source_events, +}; + +static const struct wl_message wl_data_device_requests[] = { + { "start_drag", "?oo?ou", wayland_types + 21 }, + { "set_selection", "?ou", wayland_types + 25 }, + { "release", "2", wayland_types + 0 }, +}; + +static const struct wl_message wl_data_device_events[] = { + { "data_offer", "n", wayland_types + 27 }, + { "enter", "uoff?o", wayland_types + 28 }, + { "leave", "", wayland_types + 0 }, + { "motion", "uff", wayland_types + 0 }, + { "drop", "", wayland_types + 0 }, + { "selection", "?o", wayland_types + 33 }, +}; + +WL_EXPORT const struct wl_interface wl_data_device_interface = { + "wl_data_device", 3, + 3, wl_data_device_requests, + 6, wl_data_device_events, +}; + +static const struct wl_message wl_data_device_manager_requests[] = { + { "create_data_source", "n", wayland_types + 34 }, + { "get_data_device", "no", wayland_types + 35 }, +}; + +WL_EXPORT const struct wl_interface wl_data_device_manager_interface = { + "wl_data_device_manager", 3, + 2, wl_data_device_manager_requests, + 0, NULL, +}; + +static const struct wl_message wl_shell_requests[] = { + { "get_shell_surface", "no", wayland_types + 37 }, +}; + +WL_EXPORT const struct wl_interface wl_shell_interface = { + "wl_shell", 1, + 1, wl_shell_requests, + 0, NULL, +}; + +static const struct wl_message wl_shell_surface_requests[] = { + { "pong", "u", wayland_types + 0 }, + { "move", "ou", wayland_types + 39 }, + { "resize", "ouu", wayland_types + 41 }, + { "set_toplevel", "", wayland_types + 0 }, + { "set_transient", "oiiu", wayland_types + 44 }, + { "set_fullscreen", "uu?o", wayland_types + 48 }, + { "set_popup", "ouoiiu", wayland_types + 51 }, + { "set_maximized", "?o", wayland_types + 57 }, + { "set_title", "s", wayland_types + 0 }, + { "set_class", "s", wayland_types + 0 }, +}; + +static const struct wl_message wl_shell_surface_events[] = { + { "ping", "u", wayland_types + 0 }, + { "configure", "uii", wayland_types + 0 }, + { "popup_done", "", wayland_types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_shell_surface_interface = { + "wl_shell_surface", 1, + 10, wl_shell_surface_requests, + 3, wl_shell_surface_events, +}; + +static const struct wl_message wl_surface_requests[] = { + { "destroy", "", wayland_types + 0 }, + { "attach", "?oii", wayland_types + 58 }, + { "damage", "iiii", wayland_types + 0 }, + { "frame", "n", wayland_types + 61 }, + { "set_opaque_region", "?o", wayland_types + 62 }, + { "set_input_region", "?o", wayland_types + 63 }, + { "commit", "", wayland_types + 0 }, + { "set_buffer_transform", "2i", wayland_types + 0 }, + { "set_buffer_scale", "3i", wayland_types + 0 }, + { "damage_buffer", "4iiii", wayland_types + 0 }, + { "offset", "5ii", wayland_types + 0 }, +}; + +static const struct wl_message wl_surface_events[] = { + { "enter", "o", wayland_types + 64 }, + { "leave", "o", wayland_types + 65 }, + { "preferred_buffer_scale", "6i", wayland_types + 0 }, + { "preferred_buffer_transform", "6u", wayland_types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_surface_interface = { + "wl_surface", 6, + 11, wl_surface_requests, + 4, wl_surface_events, +}; + +static const struct wl_message wl_seat_requests[] = { + { "get_pointer", "n", wayland_types + 66 }, + { "get_keyboard", "n", wayland_types + 67 }, + { "get_touch", "n", wayland_types + 68 }, + { "release", "5", wayland_types + 0 }, +}; + +static const struct wl_message wl_seat_events[] = { + { "capabilities", "u", wayland_types + 0 }, + { "name", "2s", wayland_types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_seat_interface = { + "wl_seat", 10, + 4, wl_seat_requests, + 2, wl_seat_events, +}; + +static const struct wl_message wl_pointer_requests[] = { + { "set_cursor", "u?oii", wayland_types + 69 }, + { "release", "3", wayland_types + 0 }, +}; + +static const struct wl_message wl_pointer_events[] = { + { "enter", "uoff", wayland_types + 73 }, + { "leave", "uo", wayland_types + 77 }, + { "motion", "uff", wayland_types + 0 }, + { "button", "uuuu", wayland_types + 0 }, + { "axis", "uuf", wayland_types + 0 }, + { "frame", "5", wayland_types + 0 }, + { "axis_source", "5u", wayland_types + 0 }, + { "axis_stop", "5uu", wayland_types + 0 }, + { "axis_discrete", "5ui", wayland_types + 0 }, + { "axis_value120", "8ui", wayland_types + 0 }, + { "axis_relative_direction", "9uu", wayland_types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_pointer_interface = { + "wl_pointer", 10, + 2, wl_pointer_requests, + 11, wl_pointer_events, +}; + +static const struct wl_message wl_keyboard_requests[] = { + { "release", "3", wayland_types + 0 }, +}; + +static const struct wl_message wl_keyboard_events[] = { + { "keymap", "uhu", wayland_types + 0 }, + { "enter", "uoa", wayland_types + 79 }, + { "leave", "uo", wayland_types + 82 }, + { "key", "uuuu", wayland_types + 0 }, + { "modifiers", "uuuuu", wayland_types + 0 }, + { "repeat_info", "4ii", wayland_types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_keyboard_interface = { + "wl_keyboard", 10, + 1, wl_keyboard_requests, + 6, wl_keyboard_events, +}; + +static const struct wl_message wl_touch_requests[] = { + { "release", "3", wayland_types + 0 }, +}; + +static const struct wl_message wl_touch_events[] = { + { "down", "uuoiff", wayland_types + 84 }, + { "up", "uui", wayland_types + 0 }, + { "motion", "uiff", wayland_types + 0 }, + { "frame", "", wayland_types + 0 }, + { "cancel", "", wayland_types + 0 }, + { "shape", "6iff", wayland_types + 0 }, + { "orientation", "6if", wayland_types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_touch_interface = { + "wl_touch", 10, + 1, wl_touch_requests, + 7, wl_touch_events, +}; + +static const struct wl_message wl_output_requests[] = { + { "release", "3", wayland_types + 0 }, +}; + +static const struct wl_message wl_output_events[] = { + { "geometry", "iiiiissi", wayland_types + 0 }, + { "mode", "uiii", wayland_types + 0 }, + { "done", "2", wayland_types + 0 }, + { "scale", "2i", wayland_types + 0 }, + { "name", "4s", wayland_types + 0 }, + { "description", "4s", wayland_types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_output_interface = { + "wl_output", 4, + 1, wl_output_requests, + 6, wl_output_events, +}; + +static const struct wl_message wl_region_requests[] = { + { "destroy", "", wayland_types + 0 }, + { "add", "iiii", wayland_types + 0 }, + { "subtract", "iiii", wayland_types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_region_interface = { + "wl_region", 1, + 3, wl_region_requests, + 0, NULL, +}; + +static const struct wl_message wl_subcompositor_requests[] = { + { "destroy", "", wayland_types + 0 }, + { "get_subsurface", "noo", wayland_types + 90 }, +}; + +WL_EXPORT const struct wl_interface wl_subcompositor_interface = { + "wl_subcompositor", 1, + 2, wl_subcompositor_requests, + 0, NULL, +}; + +static const struct wl_message wl_subsurface_requests[] = { + { "destroy", "", wayland_types + 0 }, + { "set_position", "ii", wayland_types + 0 }, + { "place_above", "o", wayland_types + 93 }, + { "place_below", "o", wayland_types + 94 }, + { "set_sync", "", wayland_types + 0 }, + { "set_desync", "", wayland_types + 0 }, +}; + +WL_EXPORT const struct wl_interface wl_subsurface_interface = { + "wl_subsurface", 1, + 6, wl_subsurface_requests, + 0, NULL, +}; + +static const struct wl_message wl_fixes_requests[] = { + { "destroy", "", wayland_types + 0 }, + { "destroy_registry", "o", wayland_types + 95 }, +}; + +WL_EXPORT const struct wl_interface wl_fixes_interface = { + "wl_fixes", 1, + 2, wl_fixes_requests, + 0, NULL, +}; + +#endif diff --git a/src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-client-protocol.h b/src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-client-protocol.h deleted file mode 100644 index 2b0584d750..0000000000 --- a/src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-client-protocol.h +++ /dev/null @@ -1,1292 +0,0 @@ -/* Generated by wayland-scanner 1.24.0 */ - -#ifndef WLR_OUTPUT_MANAGEMENT_UNSTABLE_V1_CLIENT_PROTOCOL_H -#define WLR_OUTPUT_MANAGEMENT_UNSTABLE_V1_CLIENT_PROTOCOL_H - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @page page_wlr_output_management_unstable_v1 The wlr_output_management_unstable_v1 protocol - * protocol to configure output devices - * - * @section page_desc_wlr_output_management_unstable_v1 Description - * - * This protocol exposes interfaces to obtain and modify output device - * configuration. - * - * Warning! The protocol described in this file is experimental and - * backward incompatible changes may be made. Backward compatible changes - * may be added together with the corresponding interface version bump. - * Backward incompatible changes are done by bumping the version number in - * the protocol and interface names and resetting the interface version. - * Once the protocol is to be declared stable, the 'z' prefix and the - * version number in the protocol and interface names are removed and the - * interface version number is reset. - * - * @section page_ifaces_wlr_output_management_unstable_v1 Interfaces - * - @subpage page_iface_zwlr_output_manager_v1 - output device configuration manager - * - @subpage page_iface_zwlr_output_head_v1 - output device - * - @subpage page_iface_zwlr_output_mode_v1 - output mode - * - @subpage page_iface_zwlr_output_configuration_v1 - output configuration - * - @subpage page_iface_zwlr_output_configuration_head_v1 - head configuration - * @section page_copyright_wlr_output_management_unstable_v1 Copyright - *
- *
- * Copyright © 2019 Purism SPC
- *
- * Permission to use, copy, modify, distribute, and sell this
- * software and its documentation for any purpose is hereby granted
- * without fee, provided that the above copyright notice appear in
- * all copies and that both that copyright notice and this permission
- * notice appear in supporting documentation, and that the name of
- * the copyright holders not be used in advertising or publicity
- * pertaining to distribution of the software without specific,
- * written prior permission.  The copyright holders make no
- * representations about the suitability of this software for any
- * purpose.  It is provided "as is" without express or implied
- * warranty.
- *
- * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
- * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
- * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
- * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
- * THIS SOFTWARE.
- * 
- */ -struct zwlr_output_configuration_head_v1; -struct zwlr_output_configuration_v1; -struct zwlr_output_head_v1; -struct zwlr_output_manager_v1; -struct zwlr_output_mode_v1; - -#ifndef ZWLR_OUTPUT_MANAGER_V1_INTERFACE - #define ZWLR_OUTPUT_MANAGER_V1_INTERFACE -/** - * @page page_iface_zwlr_output_manager_v1 zwlr_output_manager_v1 - * @section page_iface_zwlr_output_manager_v1_desc Description - * - * This interface is a manager that allows reading and writing the current - * output device configuration. - * - * Output devices that display pixels (e.g. a physical monitor or a virtual - * output in a window) are represented as heads. Heads cannot be created nor - * destroyed by the client, but they can be enabled or disabled and their - * properties can be changed. Each head may have one or more available modes. - * - * Whenever a head appears (e.g. a monitor is plugged in), it will be - * advertised via the head event. Immediately after the output manager is - * bound, all current heads are advertised. - * - * Whenever a head's properties change, the relevant wlr_output_head events - * will be sent. Not all head properties will be sent: only properties that - * have changed need to. - * - * Whenever a head disappears (e.g. a monitor is unplugged), a - * wlr_output_head.finished event will be sent. - * - * After one or more heads appear, change or disappear, the done event will - * be sent. It carries a serial which can be used in a create_configuration - * request to update heads properties. - * - * The information obtained from this protocol should only be used for output - * configuration purposes. This protocol is not designed to be a generic - * output property advertisement protocol for regular clients. Instead, - * protocols such as xdg-output should be used. - * @section page_iface_zwlr_output_manager_v1_api API - * See @ref iface_zwlr_output_manager_v1. - */ -/** - * @defgroup iface_zwlr_output_manager_v1 The zwlr_output_manager_v1 interface - * - * This interface is a manager that allows reading and writing the current - * output device configuration. - * - * Output devices that display pixels (e.g. a physical monitor or a virtual - * output in a window) are represented as heads. Heads cannot be created nor - * destroyed by the client, but they can be enabled or disabled and their - * properties can be changed. Each head may have one or more available modes. - * - * Whenever a head appears (e.g. a monitor is plugged in), it will be - * advertised via the head event. Immediately after the output manager is - * bound, all current heads are advertised. - * - * Whenever a head's properties change, the relevant wlr_output_head events - * will be sent. Not all head properties will be sent: only properties that - * have changed need to. - * - * Whenever a head disappears (e.g. a monitor is unplugged), a - * wlr_output_head.finished event will be sent. - * - * After one or more heads appear, change or disappear, the done event will - * be sent. It carries a serial which can be used in a create_configuration - * request to update heads properties. - * - * The information obtained from this protocol should only be used for output - * configuration purposes. This protocol is not designed to be a generic - * output property advertisement protocol for regular clients. Instead, - * protocols such as xdg-output should be used. - */ -extern const struct wl_interface zwlr_output_manager_v1_interface; -#endif -#ifndef ZWLR_OUTPUT_HEAD_V1_INTERFACE - #define ZWLR_OUTPUT_HEAD_V1_INTERFACE -/** - * @page page_iface_zwlr_output_head_v1 zwlr_output_head_v1 - * @section page_iface_zwlr_output_head_v1_desc Description - * - * A head is an output device. The difference between a wl_output object and - * a head is that heads are advertised even if they are turned off. A head - * object only advertises properties and cannot be used directly to change - * them. - * - * A head has some read-only properties: modes, name, description and - * physical_size. These cannot be changed by clients. - * - * Other properties can be updated via a wlr_output_configuration object. - * - * Properties sent via this interface are applied atomically via the - * wlr_output_manager.done event. No guarantees are made regarding the order - * in which properties are sent. - * @section page_iface_zwlr_output_head_v1_api API - * See @ref iface_zwlr_output_head_v1. - */ -/** - * @defgroup iface_zwlr_output_head_v1 The zwlr_output_head_v1 interface - * - * A head is an output device. The difference between a wl_output object and - * a head is that heads are advertised even if they are turned off. A head - * object only advertises properties and cannot be used directly to change - * them. - * - * A head has some read-only properties: modes, name, description and - * physical_size. These cannot be changed by clients. - * - * Other properties can be updated via a wlr_output_configuration object. - * - * Properties sent via this interface are applied atomically via the - * wlr_output_manager.done event. No guarantees are made regarding the order - * in which properties are sent. - */ -extern const struct wl_interface zwlr_output_head_v1_interface; -#endif -#ifndef ZWLR_OUTPUT_MODE_V1_INTERFACE - #define ZWLR_OUTPUT_MODE_V1_INTERFACE -/** - * @page page_iface_zwlr_output_mode_v1 zwlr_output_mode_v1 - * @section page_iface_zwlr_output_mode_v1_desc Description - * - * This object describes an output mode. - * - * Some heads don't support output modes, in which case modes won't be - * advertised. - * - * Properties sent via this interface are applied atomically via the - * wlr_output_manager.done event. No guarantees are made regarding the order - * in which properties are sent. - * @section page_iface_zwlr_output_mode_v1_api API - * See @ref iface_zwlr_output_mode_v1. - */ -/** - * @defgroup iface_zwlr_output_mode_v1 The zwlr_output_mode_v1 interface - * - * This object describes an output mode. - * - * Some heads don't support output modes, in which case modes won't be - * advertised. - * - * Properties sent via this interface are applied atomically via the - * wlr_output_manager.done event. No guarantees are made regarding the order - * in which properties are sent. - */ -extern const struct wl_interface zwlr_output_mode_v1_interface; -#endif -#ifndef ZWLR_OUTPUT_CONFIGURATION_V1_INTERFACE - #define ZWLR_OUTPUT_CONFIGURATION_V1_INTERFACE -/** - * @page page_iface_zwlr_output_configuration_v1 zwlr_output_configuration_v1 - * @section page_iface_zwlr_output_configuration_v1_desc Description - * - * This object is used by the client to describe a full output configuration. - * - * First, the client needs to setup the output configuration. Each head can - * be either enabled (and configured) or disabled. It is a protocol error to - * send two enable_head or disable_head requests with the same head. It is a - * protocol error to omit a head in a configuration. - * - * Then, the client can apply or test the configuration. The compositor will - * then reply with a succeeded, failed or cancelled event. Finally the client - * should destroy the configuration object. - * @section page_iface_zwlr_output_configuration_v1_api API - * See @ref iface_zwlr_output_configuration_v1. - */ -/** - * @defgroup iface_zwlr_output_configuration_v1 The zwlr_output_configuration_v1 interface - * - * This object is used by the client to describe a full output configuration. - * - * First, the client needs to setup the output configuration. Each head can - * be either enabled (and configured) or disabled. It is a protocol error to - * send two enable_head or disable_head requests with the same head. It is a - * protocol error to omit a head in a configuration. - * - * Then, the client can apply or test the configuration. The compositor will - * then reply with a succeeded, failed or cancelled event. Finally the client - * should destroy the configuration object. - */ -extern const struct wl_interface zwlr_output_configuration_v1_interface; -#endif -#ifndef ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_INTERFACE - #define ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_INTERFACE -/** - * @page page_iface_zwlr_output_configuration_head_v1 zwlr_output_configuration_head_v1 - * @section page_iface_zwlr_output_configuration_head_v1_desc Description - * - * This object is used by the client to update a single head's configuration. - * - * It is a protocol error to set the same property twice. - * @section page_iface_zwlr_output_configuration_head_v1_api API - * See @ref iface_zwlr_output_configuration_head_v1. - */ -/** - * @defgroup iface_zwlr_output_configuration_head_v1 The zwlr_output_configuration_head_v1 interface - * - * This object is used by the client to update a single head's configuration. - * - * It is a protocol error to set the same property twice. - */ -extern const struct wl_interface zwlr_output_configuration_head_v1_interface; -#endif - -/** - * @ingroup iface_zwlr_output_manager_v1 - * @struct zwlr_output_manager_v1_listener - */ -struct zwlr_output_manager_v1_listener { - /** - * introduce a new head - * - * This event introduces a new head. This happens whenever a new - * head appears (e.g. a monitor is plugged in) or after the output - * manager is bound. - */ - void (*head)(void* data, - struct zwlr_output_manager_v1* zwlr_output_manager_v1, - struct zwlr_output_head_v1* head); - /** - * sent all information about current configuration - * - * This event is sent after all information has been sent after - * binding to the output manager object and after any subsequent - * changes. This applies to child head and mode objects as well. In - * other words, this event is sent whenever a head or mode is - * created or destroyed and whenever one of their properties has - * been changed. Not all state is re-sent each time the current - * configuration changes: only the actual changes are sent. - * - * This allows changes to the output configuration to be seen as - * atomic, even if they happen via multiple events. - * - * A serial is sent to be used in a future create_configuration - * request. - * @param serial current configuration serial - */ - void (*done)(void* data, - struct zwlr_output_manager_v1* zwlr_output_manager_v1, - uint32_t serial); - /** - * the compositor has finished with the manager - * - * This event indicates that the compositor is done sending - * manager events. The compositor will destroy the object - * immediately after sending this event, so it will become invalid - * and the client should release any resources associated with it. - */ - void (*finished)(void* data, - struct zwlr_output_manager_v1* zwlr_output_manager_v1); -}; - -/** - * @ingroup iface_zwlr_output_manager_v1 - */ -static inline int -zwlr_output_manager_v1_add_listener(struct zwlr_output_manager_v1* zwlr_output_manager_v1, - const struct zwlr_output_manager_v1_listener* listener, - void* data) { - return wl_proxy_add_listener((struct wl_proxy*) zwlr_output_manager_v1, - (void (**)(void)) listener, - data); -} - -#define ZWLR_OUTPUT_MANAGER_V1_CREATE_CONFIGURATION 0 -#define ZWLR_OUTPUT_MANAGER_V1_STOP 1 - -/** - * @ingroup iface_zwlr_output_manager_v1 - */ -#define ZWLR_OUTPUT_MANAGER_V1_HEAD_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_output_manager_v1 - */ -#define ZWLR_OUTPUT_MANAGER_V1_DONE_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_output_manager_v1 - */ -#define ZWLR_OUTPUT_MANAGER_V1_FINISHED_SINCE_VERSION 1 - -/** - * @ingroup iface_zwlr_output_manager_v1 - */ -#define ZWLR_OUTPUT_MANAGER_V1_CREATE_CONFIGURATION_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_output_manager_v1 - */ -#define ZWLR_OUTPUT_MANAGER_V1_STOP_SINCE_VERSION 1 - -/** @ingroup iface_zwlr_output_manager_v1 */ -static inline void -zwlr_output_manager_v1_set_user_data(struct zwlr_output_manager_v1* zwlr_output_manager_v1, void* user_data) { - wl_proxy_set_user_data((struct wl_proxy*) zwlr_output_manager_v1, user_data); -} - -/** @ingroup iface_zwlr_output_manager_v1 */ -static inline void* -zwlr_output_manager_v1_get_user_data(struct zwlr_output_manager_v1* zwlr_output_manager_v1) { - return wl_proxy_get_user_data((struct wl_proxy*) zwlr_output_manager_v1); -} - -static inline uint32_t -zwlr_output_manager_v1_get_version(struct zwlr_output_manager_v1* zwlr_output_manager_v1) { - return wl_proxy_get_version((struct wl_proxy*) zwlr_output_manager_v1); -} - -/** @ingroup iface_zwlr_output_manager_v1 */ -static inline void -zwlr_output_manager_v1_destroy(struct zwlr_output_manager_v1* zwlr_output_manager_v1) { - wl_proxy_destroy((struct wl_proxy*) zwlr_output_manager_v1); -} - -// /** -// * @ingroup iface_zwlr_output_manager_v1 -// * -// * Create a new output configuration object. This allows to update head -// * properties. -// */ -// static inline struct zwlr_output_configuration_v1 * -// zwlr_output_manager_v1_create_configuration(struct zwlr_output_manager_v1 *zwlr_output_manager_v1, uint32_t serial) -// { -// struct wl_proxy *id; - -// id = wl_proxy_marshal_flags((struct wl_proxy *) zwlr_output_manager_v1, -// ZWLR_OUTPUT_MANAGER_V1_CREATE_CONFIGURATION, &zwlr_output_configuration_v1_interface, wl_proxy_get_version((struct wl_proxy *) zwlr_output_manager_v1), 0, NULL, serial); - -// return (struct zwlr_output_configuration_v1 *) id; -// } - -// /** -// * @ingroup iface_zwlr_output_manager_v1 -// * -// * Indicates the client no longer wishes to receive events for output -// * configuration changes. However the compositor may emit further events, -// * until the finished event is emitted. -// * -// * The client must not send any more requests after this one. -// */ -// static inline void -// zwlr_output_manager_v1_stop(struct zwlr_output_manager_v1 *zwlr_output_manager_v1) -// { -// wl_proxy_marshal_flags((struct wl_proxy *) zwlr_output_manager_v1, -// ZWLR_OUTPUT_MANAGER_V1_STOP, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_output_manager_v1), 0); -// } - -#ifndef ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_ENUM - #define ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_ENUM -enum zwlr_output_head_v1_adaptive_sync_state { - /** - * adaptive sync is disabled - */ - ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_DISABLED = 0, - /** - * adaptive sync is enabled - */ - ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_ENABLED = 1, -}; -#endif /* ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_ENUM */ - -/** - * @ingroup iface_zwlr_output_head_v1 - * @struct zwlr_output_head_v1_listener - */ -struct zwlr_output_head_v1_listener { - /** - * head name - * - * This event describes the head name. - * - * The naming convention is compositor defined, but limited to - * alphanumeric characters and dashes (-). Each name is unique - * among all wlr_output_head objects, but if a wlr_output_head - * object is destroyed the same name may be reused later. The names - * will also remain consistent across sessions with the same - * hardware and software configuration. - * - * Examples of names include 'HDMI-A-1', 'WL-1', 'X11-1', etc. - * However, do not assume that the name is a reflection of an - * underlying DRM connector, X11 connection, etc. - * - * If this head matches a wl_output, the wl_output.name event must - * report the same name. - * - * The name event is sent after a wlr_output_head object is - * created. This event is only sent once per object, and the name - * does not change over the lifetime of the wlr_output_head object. - */ - void (*name)(void* data, - struct zwlr_output_head_v1* zwlr_output_head_v1, - const char* name); - /** - * head description - * - * This event describes a human-readable description of the head. - * - * The description is a UTF-8 string with no convention defined for - * its contents. Examples might include 'Foocorp 11" Display' or - * 'Virtual X11 output via :1'. However, do not assume that the - * name is a reflection of the make, model, serial of the - * underlying DRM connector or the display name of the underlying - * X11 connection, etc. - * - * If this head matches a wl_output, the wl_output.description - * event must report the same name. - * - * The description event is sent after a wlr_output_head object is - * created. This event is only sent once per object, and the - * description does not change over the lifetime of the - * wlr_output_head object. - */ - void (*description)(void* data, - struct zwlr_output_head_v1* zwlr_output_head_v1, - const char* description); - /** - * head physical size - * - * This event describes the physical size of the head. This event - * is only sent if the head has a physical size (e.g. is not a - * projector or a virtual device). - * - * The physical size event is sent after a wlr_output_head object - * is created. This event is only sent once per object, and the - * physical size does not change over the lifetime of the - * wlr_output_head object. - * @param width width in millimeters of the output - * @param height height in millimeters of the output - */ - void (*physical_size)(void* data, - struct zwlr_output_head_v1* zwlr_output_head_v1, - int32_t width, - int32_t height); - /** - * introduce a mode - * - * This event introduces a mode for this head. It is sent once - * per supported mode. - */ - void (*mode)(void* data, - struct zwlr_output_head_v1* zwlr_output_head_v1, - struct zwlr_output_mode_v1* mode); - /** - * head is enabled or disabled - * - * This event describes whether the head is enabled. A disabled - * head is not mapped to a region of the global compositor space. - * - * When a head is disabled, some properties (current_mode, - * position, transform and scale) are irrelevant. - * @param enabled zero if disabled, non-zero if enabled - */ - void (*enabled)(void* data, - struct zwlr_output_head_v1* zwlr_output_head_v1, - int32_t enabled); - /** - * current mode - * - * This event describes the mode currently in use for this head. - * It is only sent if the output is enabled. - */ - void (*current_mode)(void* data, - struct zwlr_output_head_v1* zwlr_output_head_v1, - struct zwlr_output_mode_v1* mode); - /** - * current position - * - * This events describes the position of the head in the global - * compositor space. It is only sent if the output is enabled. - * @param x x position within the global compositor space - * @param y y position within the global compositor space - */ - void (*position)(void* data, - struct zwlr_output_head_v1* zwlr_output_head_v1, - int32_t x, - int32_t y); - /** - * current transformation - * - * This event describes the transformation currently applied to - * the head. It is only sent if the output is enabled. - */ - void (*transform)(void* data, - struct zwlr_output_head_v1* zwlr_output_head_v1, - int32_t transform); - /** - * current scale - * - * This events describes the scale of the head in the global - * compositor space. It is only sent if the output is enabled. - */ - void (*scale)(void* data, - struct zwlr_output_head_v1* zwlr_output_head_v1, - wl_fixed_t scale); - /** - * the head has disappeared - * - * This event indicates that the head is no longer available. The - * head object becomes inert. Clients should send a destroy request - * and release any resources associated with it. - */ - void (*finished)(void* data, - struct zwlr_output_head_v1* zwlr_output_head_v1); - /** - * head manufacturer - * - * This event describes the manufacturer of the head. - * - * Together with the model and serial_number events the purpose is - * to allow clients to recognize heads from previous sessions and - * for example load head-specific configurations back. - * - * It is not guaranteed this event will be ever sent. A reason for - * that can be that the compositor does not have information about - * the make of the head or the definition of a make is not sensible - * in the current setup, for example in a virtual session. Clients - * can still try to identify the head by available information from - * other events but should be aware that there is an increased risk - * of false positives. - * - * If sent, the make event is sent after a wlr_output_head object - * is created and only sent once per object. The make does not - * change over the lifetime of the wlr_output_head object. - * - * It is not recommended to display the make string in UI to users. - * For that the string provided by the description event should be - * preferred. - * @since 2 - */ - void (*make)(void* data, - struct zwlr_output_head_v1* zwlr_output_head_v1, - const char* make); - /** - * head model - * - * This event describes the model of the head. - * - * Together with the make and serial_number events the purpose is - * to allow clients to recognize heads from previous sessions and - * for example load head-specific configurations back. - * - * It is not guaranteed this event will be ever sent. A reason for - * that can be that the compositor does not have information about - * the model of the head or the definition of a model is not - * sensible in the current setup, for example in a virtual session. - * Clients can still try to identify the head by available - * information from other events but should be aware that there is - * an increased risk of false positives. - * - * If sent, the model event is sent after a wlr_output_head object - * is created and only sent once per object. The model does not - * change over the lifetime of the wlr_output_head object. - * - * It is not recommended to display the model string in UI to - * users. For that the string provided by the description event - * should be preferred. - * @since 2 - */ - void (*model)(void* data, - struct zwlr_output_head_v1* zwlr_output_head_v1, - const char* model); - /** - * head serial number - * - * This event describes the serial number of the head. - * - * Together with the make and model events the purpose is to allow - * clients to recognize heads from previous sessions and for - * example load head- specific configurations back. - * - * It is not guaranteed this event will be ever sent. A reason for - * that can be that the compositor does not have information about - * the serial number of the head or the definition of a serial - * number is not sensible in the current setup. Clients can still - * try to identify the head by available information from other - * events but should be aware that there is an increased risk of - * false positives. - * - * If sent, the serial number event is sent after a wlr_output_head - * object is created and only sent once per object. The serial - * number does not change over the lifetime of the wlr_output_head - * object. - * - * It is not recommended to display the serial_number string in UI - * to users. For that the string provided by the description event - * should be preferred. - * @since 2 - */ - void (*serial_number)(void* data, - struct zwlr_output_head_v1* zwlr_output_head_v1, - const char* serial_number); - /** - * current adaptive sync state - * - * This event describes whether adaptive sync is currently - * enabled for the head or not. Adaptive sync is also known as - * Variable Refresh Rate or VRR. - * @since 4 - */ - void (*adaptive_sync)(void* data, - struct zwlr_output_head_v1* zwlr_output_head_v1, - uint32_t state); -}; - -/** - * @ingroup iface_zwlr_output_head_v1 - */ -static inline int -zwlr_output_head_v1_add_listener(struct zwlr_output_head_v1* zwlr_output_head_v1, - const struct zwlr_output_head_v1_listener* listener, - void* data) { - return wl_proxy_add_listener((struct wl_proxy*) zwlr_output_head_v1, - (void (**)(void)) listener, - data); -} - -#define ZWLR_OUTPUT_HEAD_V1_RELEASE 0 - -/** - * @ingroup iface_zwlr_output_head_v1 - */ -#define ZWLR_OUTPUT_HEAD_V1_NAME_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_output_head_v1 - */ -#define ZWLR_OUTPUT_HEAD_V1_DESCRIPTION_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_output_head_v1 - */ -#define ZWLR_OUTPUT_HEAD_V1_PHYSICAL_SIZE_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_output_head_v1 - */ -#define ZWLR_OUTPUT_HEAD_V1_MODE_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_output_head_v1 - */ -#define ZWLR_OUTPUT_HEAD_V1_ENABLED_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_output_head_v1 - */ -#define ZWLR_OUTPUT_HEAD_V1_CURRENT_MODE_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_output_head_v1 - */ -#define ZWLR_OUTPUT_HEAD_V1_POSITION_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_output_head_v1 - */ -#define ZWLR_OUTPUT_HEAD_V1_TRANSFORM_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_output_head_v1 - */ -#define ZWLR_OUTPUT_HEAD_V1_SCALE_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_output_head_v1 - */ -#define ZWLR_OUTPUT_HEAD_V1_FINISHED_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_output_head_v1 - */ -#define ZWLR_OUTPUT_HEAD_V1_MAKE_SINCE_VERSION 2 -/** - * @ingroup iface_zwlr_output_head_v1 - */ -#define ZWLR_OUTPUT_HEAD_V1_MODEL_SINCE_VERSION 2 -/** - * @ingroup iface_zwlr_output_head_v1 - */ -#define ZWLR_OUTPUT_HEAD_V1_SERIAL_NUMBER_SINCE_VERSION 2 -/** - * @ingroup iface_zwlr_output_head_v1 - */ -#define ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_SINCE_VERSION 4 - -/** - * @ingroup iface_zwlr_output_head_v1 - */ -#define ZWLR_OUTPUT_HEAD_V1_RELEASE_SINCE_VERSION 3 - -/** @ingroup iface_zwlr_output_head_v1 */ -static inline void -zwlr_output_head_v1_set_user_data(struct zwlr_output_head_v1* zwlr_output_head_v1, void* user_data) { - wl_proxy_set_user_data((struct wl_proxy*) zwlr_output_head_v1, user_data); -} - -/** @ingroup iface_zwlr_output_head_v1 */ -static inline void* -zwlr_output_head_v1_get_user_data(struct zwlr_output_head_v1* zwlr_output_head_v1) { - return wl_proxy_get_user_data((struct wl_proxy*) zwlr_output_head_v1); -} - -static inline uint32_t -zwlr_output_head_v1_get_version(struct zwlr_output_head_v1* zwlr_output_head_v1) { - return wl_proxy_get_version((struct wl_proxy*) zwlr_output_head_v1); -} - -/** @ingroup iface_zwlr_output_head_v1 */ -static inline void -zwlr_output_head_v1_destroy(struct zwlr_output_head_v1* zwlr_output_head_v1) { - wl_proxy_destroy((struct wl_proxy*) zwlr_output_head_v1); -} - -// /** -// * @ingroup iface_zwlr_output_head_v1 -// * -// * This request indicates that the client will no longer use this head -// * object. -// */ -// static inline void -// zwlr_output_head_v1_release(struct zwlr_output_head_v1 *zwlr_output_head_v1) -// { -// wl_proxy_marshal_flags((struct wl_proxy *) zwlr_output_head_v1, -// ZWLR_OUTPUT_HEAD_V1_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_output_head_v1), WL_MARSHAL_FLAG_DESTROY); -// } - -/** - * @ingroup iface_zwlr_output_mode_v1 - * @struct zwlr_output_mode_v1_listener - */ -struct zwlr_output_mode_v1_listener { - /** - * mode size - * - * This event describes the mode size. The size is given in - * physical hardware units of the output device. This is not - * necessarily the same as the output size in the global compositor - * space. For instance, the output may be scaled or transformed. - * @param width width of the mode in hardware units - * @param height height of the mode in hardware units - */ - void (*size)(void* data, - struct zwlr_output_mode_v1* zwlr_output_mode_v1, - int32_t width, - int32_t height); - /** - * mode refresh rate - * - * This event describes the mode's fixed vertical refresh rate. - * It is only sent if the mode has a fixed refresh rate. - * @param refresh vertical refresh rate in mHz - */ - void (*refresh)(void* data, - struct zwlr_output_mode_v1* zwlr_output_mode_v1, - int32_t refresh); - /** - * mode is preferred - * - * This event advertises this mode as preferred. - */ - void (*preferred)(void* data, - struct zwlr_output_mode_v1* zwlr_output_mode_v1); - /** - * the mode has disappeared - * - * This event indicates that the mode is no longer available. The - * mode object becomes inert. Clients should send a destroy request - * and release any resources associated with it. - */ - void (*finished)(void* data, - struct zwlr_output_mode_v1* zwlr_output_mode_v1); -}; - -/** - * @ingroup iface_zwlr_output_mode_v1 - */ -static inline int -zwlr_output_mode_v1_add_listener(struct zwlr_output_mode_v1* zwlr_output_mode_v1, - const struct zwlr_output_mode_v1_listener* listener, - void* data) { - return wl_proxy_add_listener((struct wl_proxy*) zwlr_output_mode_v1, - (void (**)(void)) listener, - data); -} - -#define ZWLR_OUTPUT_MODE_V1_RELEASE 0 - -/** - * @ingroup iface_zwlr_output_mode_v1 - */ -#define ZWLR_OUTPUT_MODE_V1_SIZE_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_output_mode_v1 - */ -#define ZWLR_OUTPUT_MODE_V1_REFRESH_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_output_mode_v1 - */ -#define ZWLR_OUTPUT_MODE_V1_PREFERRED_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_output_mode_v1 - */ -#define ZWLR_OUTPUT_MODE_V1_FINISHED_SINCE_VERSION 1 - -/** - * @ingroup iface_zwlr_output_mode_v1 - */ -#define ZWLR_OUTPUT_MODE_V1_RELEASE_SINCE_VERSION 3 - -/** @ingroup iface_zwlr_output_mode_v1 */ -static inline void -zwlr_output_mode_v1_set_user_data(struct zwlr_output_mode_v1* zwlr_output_mode_v1, void* user_data) { - wl_proxy_set_user_data((struct wl_proxy*) zwlr_output_mode_v1, user_data); -} - -/** @ingroup iface_zwlr_output_mode_v1 */ -static inline void* -zwlr_output_mode_v1_get_user_data(struct zwlr_output_mode_v1* zwlr_output_mode_v1) { - return wl_proxy_get_user_data((struct wl_proxy*) zwlr_output_mode_v1); -} - -static inline uint32_t -zwlr_output_mode_v1_get_version(struct zwlr_output_mode_v1* zwlr_output_mode_v1) { - return wl_proxy_get_version((struct wl_proxy*) zwlr_output_mode_v1); -} - -/** @ingroup iface_zwlr_output_mode_v1 */ -static inline void -zwlr_output_mode_v1_destroy(struct zwlr_output_mode_v1* zwlr_output_mode_v1) { - wl_proxy_destroy((struct wl_proxy*) zwlr_output_mode_v1); -} - -// /** -// * @ingroup iface_zwlr_output_mode_v1 -// * -// * This request indicates that the client will no longer use this mode -// * object. -// */ -// static inline void -// zwlr_output_mode_v1_release(struct zwlr_output_mode_v1 *zwlr_output_mode_v1) -// { -// wl_proxy_marshal_flags((struct wl_proxy *) zwlr_output_mode_v1, -// ZWLR_OUTPUT_MODE_V1_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_output_mode_v1), WL_MARSHAL_FLAG_DESTROY); -// } - -#ifndef ZWLR_OUTPUT_CONFIGURATION_V1_ERROR_ENUM - #define ZWLR_OUTPUT_CONFIGURATION_V1_ERROR_ENUM -enum zwlr_output_configuration_v1_error { - /** - * head has been configured twice - */ - ZWLR_OUTPUT_CONFIGURATION_V1_ERROR_ALREADY_CONFIGURED_HEAD = 1, - /** - * head has not been configured - */ - ZWLR_OUTPUT_CONFIGURATION_V1_ERROR_UNCONFIGURED_HEAD = 2, - /** - * request sent after configuration has been applied or tested - */ - ZWLR_OUTPUT_CONFIGURATION_V1_ERROR_ALREADY_USED = 3, -}; -#endif /* ZWLR_OUTPUT_CONFIGURATION_V1_ERROR_ENUM */ - -/** - * @ingroup iface_zwlr_output_configuration_v1 - * @struct zwlr_output_configuration_v1_listener - */ -struct zwlr_output_configuration_v1_listener { - /** - * configuration changes succeeded - * - * Sent after the compositor has successfully applied the changes - * or tested them. - * - * Upon receiving this event, the client should destroy this - * object. - * - * If the current configuration has changed, events to describe the - * changes will be sent followed by a wlr_output_manager.done - * event. - */ - void (*succeeded)(void* data, - struct zwlr_output_configuration_v1* zwlr_output_configuration_v1); - /** - * configuration changes failed - * - * Sent if the compositor rejects the changes or failed to apply - * them. The compositor should revert any changes made by the apply - * request that triggered this event. - * - * Upon receiving this event, the client should destroy this - * object. - */ - void (*failed)(void* data, - struct zwlr_output_configuration_v1* zwlr_output_configuration_v1); - /** - * configuration has been cancelled - * - * Sent if the compositor cancels the configuration because the - * state of an output changed and the client has outdated - * information (e.g. after an output has been hotplugged). - * - * The client can create a new configuration with a newer serial - * and try again. - * - * Upon receiving this event, the client should destroy this - * object. - */ - void (*cancelled)(void* data, - struct zwlr_output_configuration_v1* zwlr_output_configuration_v1); -}; - -/** - * @ingroup iface_zwlr_output_configuration_v1 - */ -static inline int -zwlr_output_configuration_v1_add_listener(struct zwlr_output_configuration_v1* zwlr_output_configuration_v1, - const struct zwlr_output_configuration_v1_listener* listener, - void* data) { - return wl_proxy_add_listener((struct wl_proxy*) zwlr_output_configuration_v1, - (void (**)(void)) listener, - data); -} - -#define ZWLR_OUTPUT_CONFIGURATION_V1_ENABLE_HEAD 0 -#define ZWLR_OUTPUT_CONFIGURATION_V1_DISABLE_HEAD 1 -#define ZWLR_OUTPUT_CONFIGURATION_V1_APPLY 2 -#define ZWLR_OUTPUT_CONFIGURATION_V1_TEST 3 -#define ZWLR_OUTPUT_CONFIGURATION_V1_DESTROY 4 - -/** - * @ingroup iface_zwlr_output_configuration_v1 - */ -#define ZWLR_OUTPUT_CONFIGURATION_V1_SUCCEEDED_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_output_configuration_v1 - */ -#define ZWLR_OUTPUT_CONFIGURATION_V1_FAILED_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_output_configuration_v1 - */ -#define ZWLR_OUTPUT_CONFIGURATION_V1_CANCELLED_SINCE_VERSION 1 - -/** - * @ingroup iface_zwlr_output_configuration_v1 - */ -#define ZWLR_OUTPUT_CONFIGURATION_V1_ENABLE_HEAD_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_output_configuration_v1 - */ -#define ZWLR_OUTPUT_CONFIGURATION_V1_DISABLE_HEAD_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_output_configuration_v1 - */ -#define ZWLR_OUTPUT_CONFIGURATION_V1_APPLY_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_output_configuration_v1 - */ -#define ZWLR_OUTPUT_CONFIGURATION_V1_TEST_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_output_configuration_v1 - */ -#define ZWLR_OUTPUT_CONFIGURATION_V1_DESTROY_SINCE_VERSION 1 - -/** @ingroup iface_zwlr_output_configuration_v1 */ -static inline void -zwlr_output_configuration_v1_set_user_data(struct zwlr_output_configuration_v1* zwlr_output_configuration_v1, void* user_data) { - wl_proxy_set_user_data((struct wl_proxy*) zwlr_output_configuration_v1, user_data); -} - -/** @ingroup iface_zwlr_output_configuration_v1 */ -static inline void* -zwlr_output_configuration_v1_get_user_data(struct zwlr_output_configuration_v1* zwlr_output_configuration_v1) { - return wl_proxy_get_user_data((struct wl_proxy*) zwlr_output_configuration_v1); -} - -static inline uint32_t -zwlr_output_configuration_v1_get_version(struct zwlr_output_configuration_v1* zwlr_output_configuration_v1) { - return wl_proxy_get_version((struct wl_proxy*) zwlr_output_configuration_v1); -} - -// /** -// * @ingroup iface_zwlr_output_configuration_v1 -// * -// * Enable a head. This request creates a head configuration object that can -// * be used to change the head's properties. -// */ -// static inline struct zwlr_output_configuration_head_v1 * -// zwlr_output_configuration_v1_enable_head(struct zwlr_output_configuration_v1 *zwlr_output_configuration_v1, struct zwlr_output_head_v1 *head) -// { -// struct wl_proxy *id; - -// id = wl_proxy_marshal_flags((struct wl_proxy *) zwlr_output_configuration_v1, -// ZWLR_OUTPUT_CONFIGURATION_V1_ENABLE_HEAD, &zwlr_output_configuration_head_v1_interface, wl_proxy_get_version((struct wl_proxy *) zwlr_output_configuration_v1), 0, NULL, head); - -// return (struct zwlr_output_configuration_head_v1 *) id; -// } - -// /** -// * @ingroup iface_zwlr_output_configuration_v1 -// * -// * Disable a head. -// */ -// static inline void -// zwlr_output_configuration_v1_disable_head(struct zwlr_output_configuration_v1 *zwlr_output_configuration_v1, struct zwlr_output_head_v1 *head) -// { -// wl_proxy_marshal_flags((struct wl_proxy *) zwlr_output_configuration_v1, -// ZWLR_OUTPUT_CONFIGURATION_V1_DISABLE_HEAD, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_output_configuration_v1), 0, head); -// } - -// /** -// * @ingroup iface_zwlr_output_configuration_v1 -// * -// * Apply the new output configuration. -// * -// * In case the configuration is successfully applied, there is no guarantee -// * that the new output state matches completely the requested -// * configuration. For instance, a compositor might round the scale if it -// * doesn't support fractional scaling. -// * -// * After this request has been sent, the compositor must respond with an -// * succeeded, failed or cancelled event. Sending a request that isn't the -// * destructor is a protocol error. -// */ -// static inline void -// zwlr_output_configuration_v1_apply(struct zwlr_output_configuration_v1 *zwlr_output_configuration_v1) -// { -// wl_proxy_marshal_flags((struct wl_proxy *) zwlr_output_configuration_v1, -// ZWLR_OUTPUT_CONFIGURATION_V1_APPLY, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_output_configuration_v1), 0); -// } - -// /** -// * @ingroup iface_zwlr_output_configuration_v1 -// * -// * Test the new output configuration. The configuration won't be applied, -// * but will only be validated. -// * -// * Even if the compositor succeeds to test a configuration, applying it may -// * fail. -// * -// * After this request has been sent, the compositor must respond with an -// * succeeded, failed or cancelled event. Sending a request that isn't the -// * destructor is a protocol error. -// */ -// static inline void -// zwlr_output_configuration_v1_test(struct zwlr_output_configuration_v1 *zwlr_output_configuration_v1) -// { -// wl_proxy_marshal_flags((struct wl_proxy *) zwlr_output_configuration_v1, -// ZWLR_OUTPUT_CONFIGURATION_V1_TEST, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_output_configuration_v1), 0); -// } - -// /** -// * @ingroup iface_zwlr_output_configuration_v1 -// * -// * Using this request a client can tell the compositor that it is not going -// * to use the configuration object anymore. Any changes to the outputs -// * that have not been applied will be discarded. -// * -// * This request also destroys wlr_output_configuration_head objects created -// * via this object. -// */ -// static inline void -// zwlr_output_configuration_v1_destroy(struct zwlr_output_configuration_v1 *zwlr_output_configuration_v1) -// { -// wl_proxy_marshal_flags((struct wl_proxy *) zwlr_output_configuration_v1, -// ZWLR_OUTPUT_CONFIGURATION_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_output_configuration_v1), WL_MARSHAL_FLAG_DESTROY); -// } - -#ifndef ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ENUM - #define ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ENUM -enum zwlr_output_configuration_head_v1_error { - /** - * property has already been set - */ - ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET = 1, - /** - * mode doesn't belong to head - */ - ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_INVALID_MODE = 2, - /** - * mode is invalid - */ - ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_INVALID_CUSTOM_MODE = 3, - /** - * transform value outside enum - */ - ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_INVALID_TRANSFORM = 4, - /** - * scale negative or zero - */ - ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_INVALID_SCALE = 5, - /** - * invalid enum value used in the set_adaptive_sync request - * @since 4 - */ - ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_INVALID_ADAPTIVE_SYNC_STATE = 6, -}; - /** - * @ingroup iface_zwlr_output_configuration_head_v1 - */ - #define ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_INVALID_ADAPTIVE_SYNC_STATE_SINCE_VERSION 4 -#endif /* ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ENUM */ - -#define ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_MODE 0 -#define ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_CUSTOM_MODE 1 -#define ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_POSITION 2 -#define ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_TRANSFORM 3 -#define ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_SCALE 4 -#define ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_ADAPTIVE_SYNC 5 - -/** - * @ingroup iface_zwlr_output_configuration_head_v1 - */ -#define ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_MODE_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_output_configuration_head_v1 - */ -#define ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_CUSTOM_MODE_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_output_configuration_head_v1 - */ -#define ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_POSITION_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_output_configuration_head_v1 - */ -#define ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_TRANSFORM_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_output_configuration_head_v1 - */ -#define ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_SCALE_SINCE_VERSION 1 -/** - * @ingroup iface_zwlr_output_configuration_head_v1 - */ -#define ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_ADAPTIVE_SYNC_SINCE_VERSION 4 - -/** @ingroup iface_zwlr_output_configuration_head_v1 */ -static inline void -zwlr_output_configuration_head_v1_set_user_data(struct zwlr_output_configuration_head_v1* zwlr_output_configuration_head_v1, void* user_data) { - wl_proxy_set_user_data((struct wl_proxy*) zwlr_output_configuration_head_v1, user_data); -} - -/** @ingroup iface_zwlr_output_configuration_head_v1 */ -static inline void* -zwlr_output_configuration_head_v1_get_user_data(struct zwlr_output_configuration_head_v1* zwlr_output_configuration_head_v1) { - return wl_proxy_get_user_data((struct wl_proxy*) zwlr_output_configuration_head_v1); -} - -static inline uint32_t -zwlr_output_configuration_head_v1_get_version(struct zwlr_output_configuration_head_v1* zwlr_output_configuration_head_v1) { - return wl_proxy_get_version((struct wl_proxy*) zwlr_output_configuration_head_v1); -} - -/** @ingroup iface_zwlr_output_configuration_head_v1 */ -static inline void -zwlr_output_configuration_head_v1_destroy(struct zwlr_output_configuration_head_v1* zwlr_output_configuration_head_v1) { - wl_proxy_destroy((struct wl_proxy*) zwlr_output_configuration_head_v1); -} - -// /** -// * @ingroup iface_zwlr_output_configuration_head_v1 -// * -// * This request sets the head's mode. -// */ -// static inline void -// zwlr_output_configuration_head_v1_set_mode(struct zwlr_output_configuration_head_v1 *zwlr_output_configuration_head_v1, struct zwlr_output_mode_v1 *mode) -// { -// wl_proxy_marshal_flags((struct wl_proxy *) zwlr_output_configuration_head_v1, -// ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_MODE, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_output_configuration_head_v1), 0, mode); -// } - -// /** -// * @ingroup iface_zwlr_output_configuration_head_v1 -// * -// * This request assigns a custom mode to the head. The size is given in -// * physical hardware units of the output device. If set to zero, the -// * refresh rate is unspecified. -// * -// * It is a protocol error to set both a mode and a custom mode. -// */ -// static inline void -// zwlr_output_configuration_head_v1_set_custom_mode(struct zwlr_output_configuration_head_v1 *zwlr_output_configuration_head_v1, int32_t width, int32_t height, int32_t refresh) -// { -// wl_proxy_marshal_flags((struct wl_proxy *) zwlr_output_configuration_head_v1, -// ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_CUSTOM_MODE, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_output_configuration_head_v1), 0, width, height, refresh); -// } - -// /** -// * @ingroup iface_zwlr_output_configuration_head_v1 -// * -// * This request sets the head's position in the global compositor space. -// */ -// static inline void -// zwlr_output_configuration_head_v1_set_position(struct zwlr_output_configuration_head_v1 *zwlr_output_configuration_head_v1, int32_t x, int32_t y) -// { -// wl_proxy_marshal_flags((struct wl_proxy *) zwlr_output_configuration_head_v1, -// ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_POSITION, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_output_configuration_head_v1), 0, x, y); -// } - -// /** -// * @ingroup iface_zwlr_output_configuration_head_v1 -// * -// * This request sets the head's transform. -// */ -// static inline void -// zwlr_output_configuration_head_v1_set_transform(struct zwlr_output_configuration_head_v1 *zwlr_output_configuration_head_v1, int32_t transform) -// { -// wl_proxy_marshal_flags((struct wl_proxy *) zwlr_output_configuration_head_v1, -// ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_TRANSFORM, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_output_configuration_head_v1), 0, transform); -// } - -// /** -// * @ingroup iface_zwlr_output_configuration_head_v1 -// * -// * This request sets the head's scale. -// */ -// static inline void -// zwlr_output_configuration_head_v1_set_scale(struct zwlr_output_configuration_head_v1 *zwlr_output_configuration_head_v1, wl_fixed_t scale) -// { -// wl_proxy_marshal_flags((struct wl_proxy *) zwlr_output_configuration_head_v1, -// ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_SCALE, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_output_configuration_head_v1), 0, scale); -// } - -// /** -// * @ingroup iface_zwlr_output_configuration_head_v1 -// * -// * This request enables/disables adaptive sync. Adaptive sync is also -// * known as Variable Refresh Rate or VRR. -// */ -// static inline void -// zwlr_output_configuration_head_v1_set_adaptive_sync(struct zwlr_output_configuration_head_v1 *zwlr_output_configuration_head_v1, uint32_t state) -// { -// wl_proxy_marshal_flags((struct wl_proxy *) zwlr_output_configuration_head_v1, -// ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_ADAPTIVE_SYNC, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_output_configuration_head_v1), 0, state); -// } - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-protocol.c b/src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-protocol.c deleted file mode 100644 index a231fd4816..0000000000 --- a/src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-protocol.c +++ /dev/null @@ -1,176 +0,0 @@ -#ifdef FF_HAVE_WAYLAND - -/* Generated by wayland-scanner 1.24.0 */ - -/* - * Copyright © 2019 Purism SPC - * - * Permission to use, copy, modify, distribute, and sell this - * software and its documentation for any purpose is hereby granted - * without fee, provided that the above copyright notice appear in - * all copies and that both that copyright notice and this permission - * notice appear in supporting documentation, and that the name of - * the copyright holders not be used in advertising or publicity - * pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no - * representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied - * warranty. - * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS - * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY - * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN - * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, - * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF - * THIS SOFTWARE. - */ - - #include - #include - #include - #include - - #ifndef __has_attribute - #define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ - #endif - - #if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) - #define WL_PRIVATE __attribute__((visibility("hidden"))) - #else - #define WL_PRIVATE - #endif - -extern const struct wl_interface zwlr_output_configuration_head_v1_interface; -extern const struct wl_interface zwlr_output_configuration_v1_interface; -extern const struct wl_interface zwlr_output_head_v1_interface; -extern const struct wl_interface zwlr_output_mode_v1_interface; - -static const struct wl_interface* wlr_output_management_unstable_v1_types[] = { - NULL, - NULL, - NULL, - &zwlr_output_configuration_v1_interface, - NULL, - &zwlr_output_head_v1_interface, - &zwlr_output_mode_v1_interface, - &zwlr_output_mode_v1_interface, - &zwlr_output_configuration_head_v1_interface, - &zwlr_output_head_v1_interface, - &zwlr_output_head_v1_interface, - &zwlr_output_mode_v1_interface, -}; - -static const struct wl_message zwlr_output_manager_v1_requests[] = { - { "create_configuration", "nu", wlr_output_management_unstable_v1_types + 3 }, - { "stop", "", wlr_output_management_unstable_v1_types + 0 }, -}; - -static const struct wl_message zwlr_output_manager_v1_events[] = { - { "head", "n", wlr_output_management_unstable_v1_types + 5 }, - { "done", "u", wlr_output_management_unstable_v1_types + 0 }, - { "finished", "", wlr_output_management_unstable_v1_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface zwlr_output_manager_v1_interface = { - "zwlr_output_manager_v1", - 4, - 2, - zwlr_output_manager_v1_requests, - 3, - zwlr_output_manager_v1_events, -}; - -static const struct wl_message zwlr_output_head_v1_requests[] = { - { "release", "3", wlr_output_management_unstable_v1_types + 0 }, -}; - -static const struct wl_message zwlr_output_head_v1_events[] = { - { "name", "s", wlr_output_management_unstable_v1_types + 0 }, - { "description", "s", wlr_output_management_unstable_v1_types + 0 }, - { "physical_size", "ii", wlr_output_management_unstable_v1_types + 0 }, - { "mode", "n", wlr_output_management_unstable_v1_types + 6 }, - { "enabled", "i", wlr_output_management_unstable_v1_types + 0 }, - { "current_mode", "o", wlr_output_management_unstable_v1_types + 7 }, - { "position", "ii", wlr_output_management_unstable_v1_types + 0 }, - { "transform", "i", wlr_output_management_unstable_v1_types + 0 }, - { "scale", "f", wlr_output_management_unstable_v1_types + 0 }, - { "finished", "", wlr_output_management_unstable_v1_types + 0 }, - { "make", "2s", wlr_output_management_unstable_v1_types + 0 }, - { "model", "2s", wlr_output_management_unstable_v1_types + 0 }, - { "serial_number", "2s", wlr_output_management_unstable_v1_types + 0 }, - { "adaptive_sync", "4u", wlr_output_management_unstable_v1_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface zwlr_output_head_v1_interface = { - "zwlr_output_head_v1", - 4, - 1, - zwlr_output_head_v1_requests, - 14, - zwlr_output_head_v1_events, -}; - -static const struct wl_message zwlr_output_mode_v1_requests[] = { - { "release", "3", wlr_output_management_unstable_v1_types + 0 }, -}; - -static const struct wl_message zwlr_output_mode_v1_events[] = { - { "size", "ii", wlr_output_management_unstable_v1_types + 0 }, - { "refresh", "i", wlr_output_management_unstable_v1_types + 0 }, - { "preferred", "", wlr_output_management_unstable_v1_types + 0 }, - { "finished", "", wlr_output_management_unstable_v1_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface zwlr_output_mode_v1_interface = { - "zwlr_output_mode_v1", - 3, - 1, - zwlr_output_mode_v1_requests, - 4, - zwlr_output_mode_v1_events, -}; - -static const struct wl_message zwlr_output_configuration_v1_requests[] = { - { "enable_head", "no", wlr_output_management_unstable_v1_types + 8 }, - { "disable_head", "o", wlr_output_management_unstable_v1_types + 10 }, - { "apply", "", wlr_output_management_unstable_v1_types + 0 }, - { "test", "", wlr_output_management_unstable_v1_types + 0 }, - { "destroy", "", wlr_output_management_unstable_v1_types + 0 }, -}; - -static const struct wl_message zwlr_output_configuration_v1_events[] = { - { "succeeded", "", wlr_output_management_unstable_v1_types + 0 }, - { "failed", "", wlr_output_management_unstable_v1_types + 0 }, - { "cancelled", "", wlr_output_management_unstable_v1_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface zwlr_output_configuration_v1_interface = { - "zwlr_output_configuration_v1", - 4, - 5, - zwlr_output_configuration_v1_requests, - 3, - zwlr_output_configuration_v1_events, -}; - -static const struct wl_message zwlr_output_configuration_head_v1_requests[] = { - { "set_mode", "o", wlr_output_management_unstable_v1_types + 11 }, - { "set_custom_mode", "iii", wlr_output_management_unstable_v1_types + 0 }, - { "set_position", "ii", wlr_output_management_unstable_v1_types + 0 }, - { "set_transform", "i", wlr_output_management_unstable_v1_types + 0 }, - { "set_scale", "f", wlr_output_management_unstable_v1_types + 0 }, - { "set_adaptive_sync", "4u", wlr_output_management_unstable_v1_types + 0 }, -}; - -WL_PRIVATE const struct wl_interface zwlr_output_configuration_head_v1_interface = { - "zwlr_output_configuration_head_v1", - 4, - 6, - zwlr_output_configuration_head_v1_requests, - 0, - NULL, -}; - -#endif diff --git a/src/detection/displayserver/linux/wayland/wp-color-management-v1-client-protocol.h b/src/detection/displayserver/linux/wayland/wp-color-management-v1-client-protocol.h new file mode 100644 index 0000000000..5db1d71216 --- /dev/null +++ b/src/detection/displayserver/linux/wayland/wp-color-management-v1-client-protocol.h @@ -0,0 +1,2871 @@ +/* Generated by wayland-scanner 1.24.0 */ + +#ifndef COLOR_MANAGEMENT_V1_CLIENT_PROTOCOL_H +#define COLOR_MANAGEMENT_V1_CLIENT_PROTOCOL_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_color_management_v1 The color_management_v1 protocol + * color management protocol + * + * @section page_desc_color_management_v1 Description + * + * The aim of the color management extension is to allow clients to know + * the color properties of outputs, and to tell the compositor about the color + * properties of their content on surfaces. All surface contents must be + * readily intended for some display, but not necessarily for the display at + * hand. Doing this enables a compositor to perform automatic color management + * of content for different outputs according to how content is intended to + * look like. + * + * For an introduction, see the section "Color management" in the Wayland + * documentation at https://wayland.freedesktop.org/docs/html/ . + * + * The color properties are represented as an image description object which + * is immutable after it has been created. A wl_output always has an + * associated image description that clients can observe. A wl_surface + * always has an associated preferred image description as a hint chosen by + * the compositor that clients can also observe. Clients can set an image + * description on a wl_surface to denote the color characteristics of the + * surface contents. + * + * An image description essentially defines a display and (indirectly) its + * viewing environment. An image description includes SDR and HDR colorimetry + * and encoding, HDR metadata, and some parameters related to the viewing + * environment. An image description does not include the properties set + * through color-representation extension. It is expected that the + * color-representation extension is used in conjunction with the + * color-management extension when necessary, particularly with the YUV family + * of pixel formats. + * + * The normative appendix for this protocol is in the appendix.md file beside + * this XML file. + * + * The color-and-hdr repository + * (https://gitlab.freedesktop.org/pq/color-and-hdr) contains + * background information on the protocol design and legacy color management. + * It also contains a glossary, learning resources for digital color, tools, + * samples and more. + * + * The terminology used in this protocol is based on common color science and + * color encoding terminology where possible. The glossary in the color-and-hdr + * repository shall be the authority on the definition of terms in this + * protocol. + * + * Warning! The protocol described in this file is currently in the testing + * phase. Backward compatible changes may be added together with the + * corresponding interface version bump. Backward incompatible changes can + * only be done by creating a new major version of the extension. + * + * @section page_ifaces_color_management_v1 Interfaces + * - @subpage page_iface_wp_color_manager_v1 - color manager singleton + * - @subpage page_iface_wp_color_management_output_v1 - output color properties + * - @subpage page_iface_wp_color_management_surface_v1 - color management extension to a surface + * - @subpage page_iface_wp_color_management_surface_feedback_v1 - color management extension to a surface + * - @subpage page_iface_wp_image_description_creator_icc_v1 - holder of image description ICC information + * - @subpage page_iface_wp_image_description_creator_params_v1 - holder of image description parameters + * - @subpage page_iface_wp_image_description_v1 - Colorimetric image description + * - @subpage page_iface_wp_image_description_info_v1 - Colorimetric image description information + * - @subpage page_iface_wp_image_description_reference_v1 - Reference to an image description + * @section page_copyright_color_management_v1 Copyright + *
+ *
+ * Copyright 2019 Sebastian Wick
+ * Copyright 2019 Erwin Burema
+ * Copyright 2020 AMD
+ * Copyright 2020-2024 Collabora, Ltd.
+ * Copyright 2024 Xaver Hugl
+ * Copyright 2022-2025 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ */ +struct wl_output; +struct wl_surface; +struct wp_color_management_output_v1; +struct wp_color_management_surface_feedback_v1; +struct wp_color_management_surface_v1; +struct wp_color_manager_v1; +struct wp_image_description_creator_icc_v1; +struct wp_image_description_creator_params_v1; +struct wp_image_description_info_v1; +struct wp_image_description_reference_v1; +struct wp_image_description_v1; + +#ifndef WP_COLOR_MANAGER_V1_INTERFACE +#define WP_COLOR_MANAGER_V1_INTERFACE +/** + * @page page_iface_wp_color_manager_v1 wp_color_manager_v1 + * @section page_iface_wp_color_manager_v1_desc Description + * + * A singleton global interface used for getting color management extensions + * for wl_surface and wl_output objects, and for creating client defined + * image description objects. The extension interfaces allow + * getting the image description of outputs and setting the image + * description of surfaces. + * + * Compositors should never remove this global. + * @section page_iface_wp_color_manager_v1_api API + * See @ref iface_wp_color_manager_v1. + */ +/** + * @defgroup iface_wp_color_manager_v1 The wp_color_manager_v1 interface + * + * A singleton global interface used for getting color management extensions + * for wl_surface and wl_output objects, and for creating client defined + * image description objects. The extension interfaces allow + * getting the image description of outputs and setting the image + * description of surfaces. + * + * Compositors should never remove this global. + */ +extern const struct wl_interface wp_color_manager_v1_interface; +#endif +#ifndef WP_COLOR_MANAGEMENT_OUTPUT_V1_INTERFACE +#define WP_COLOR_MANAGEMENT_OUTPUT_V1_INTERFACE +/** + * @page page_iface_wp_color_management_output_v1 wp_color_management_output_v1 + * @section page_iface_wp_color_management_output_v1_desc Description + * + * A wp_color_management_output_v1 describes the color properties of an + * output. + * + * The wp_color_management_output_v1 is associated with the wl_output global + * underlying the wl_output object. Therefore the client destroying the + * wl_output object has no impact, but the compositor removing the output + * global makes the wp_color_management_output_v1 object inert. + * @section page_iface_wp_color_management_output_v1_api API + * See @ref iface_wp_color_management_output_v1. + */ +/** + * @defgroup iface_wp_color_management_output_v1 The wp_color_management_output_v1 interface + * + * A wp_color_management_output_v1 describes the color properties of an + * output. + * + * The wp_color_management_output_v1 is associated with the wl_output global + * underlying the wl_output object. Therefore the client destroying the + * wl_output object has no impact, but the compositor removing the output + * global makes the wp_color_management_output_v1 object inert. + */ +extern const struct wl_interface wp_color_management_output_v1_interface; +#endif +#ifndef WP_COLOR_MANAGEMENT_SURFACE_V1_INTERFACE +#define WP_COLOR_MANAGEMENT_SURFACE_V1_INTERFACE +/** + * @page page_iface_wp_color_management_surface_v1 wp_color_management_surface_v1 + * @section page_iface_wp_color_management_surface_v1_desc Description + * + * A wp_color_management_surface_v1 allows the client to set the color + * space and HDR properties of a surface. + * + * If the wl_surface associated with the wp_color_management_surface_v1 is + * destroyed, the wp_color_management_surface_v1 object becomes inert. + * @section page_iface_wp_color_management_surface_v1_api API + * See @ref iface_wp_color_management_surface_v1. + */ +/** + * @defgroup iface_wp_color_management_surface_v1 The wp_color_management_surface_v1 interface + * + * A wp_color_management_surface_v1 allows the client to set the color + * space and HDR properties of a surface. + * + * If the wl_surface associated with the wp_color_management_surface_v1 is + * destroyed, the wp_color_management_surface_v1 object becomes inert. + */ +extern const struct wl_interface wp_color_management_surface_v1_interface; +#endif +#ifndef WP_COLOR_MANAGEMENT_SURFACE_FEEDBACK_V1_INTERFACE +#define WP_COLOR_MANAGEMENT_SURFACE_FEEDBACK_V1_INTERFACE +/** + * @page page_iface_wp_color_management_surface_feedback_v1 wp_color_management_surface_feedback_v1 + * @section page_iface_wp_color_management_surface_feedback_v1_desc Description + * + * A wp_color_management_surface_feedback_v1 allows the client to get the + * preferred image description of a surface. + * + * If the wl_surface associated with this object is destroyed, the + * wp_color_management_surface_feedback_v1 object becomes inert. + * @section page_iface_wp_color_management_surface_feedback_v1_api API + * See @ref iface_wp_color_management_surface_feedback_v1. + */ +/** + * @defgroup iface_wp_color_management_surface_feedback_v1 The wp_color_management_surface_feedback_v1 interface + * + * A wp_color_management_surface_feedback_v1 allows the client to get the + * preferred image description of a surface. + * + * If the wl_surface associated with this object is destroyed, the + * wp_color_management_surface_feedback_v1 object becomes inert. + */ +extern const struct wl_interface wp_color_management_surface_feedback_v1_interface; +#endif +#ifndef WP_IMAGE_DESCRIPTION_CREATOR_ICC_V1_INTERFACE +#define WP_IMAGE_DESCRIPTION_CREATOR_ICC_V1_INTERFACE +/** + * @page page_iface_wp_image_description_creator_icc_v1 wp_image_description_creator_icc_v1 + * @section page_iface_wp_image_description_creator_icc_v1_desc Description + * + * This type of object is used for collecting all the information required + * to create a wp_image_description_v1 object from an ICC file. A complete + * set of required parameters consists of these properties: + * - ICC file + * + * Each required property must be set exactly once if the client is to create + * an image description. The set requests verify that a property was not + * already set. The create request verifies that all required properties are + * set. There may be several alternative requests for setting each property, + * and in that case the client must choose one of them. + * + * Once all properties have been set, the create request must be used to + * create the image description object, destroying the creator in the + * process. + * + * The link between a pixel value (a device value in ICC) and its respective + * colorimetry is defined by the details of the particular ICC profile. + * Those details also determine when colorimetry becomes undefined. + * @section page_iface_wp_image_description_creator_icc_v1_api API + * See @ref iface_wp_image_description_creator_icc_v1. + */ +/** + * @defgroup iface_wp_image_description_creator_icc_v1 The wp_image_description_creator_icc_v1 interface + * + * This type of object is used for collecting all the information required + * to create a wp_image_description_v1 object from an ICC file. A complete + * set of required parameters consists of these properties: + * - ICC file + * + * Each required property must be set exactly once if the client is to create + * an image description. The set requests verify that a property was not + * already set. The create request verifies that all required properties are + * set. There may be several alternative requests for setting each property, + * and in that case the client must choose one of them. + * + * Once all properties have been set, the create request must be used to + * create the image description object, destroying the creator in the + * process. + * + * The link between a pixel value (a device value in ICC) and its respective + * colorimetry is defined by the details of the particular ICC profile. + * Those details also determine when colorimetry becomes undefined. + */ +extern const struct wl_interface wp_image_description_creator_icc_v1_interface; +#endif +#ifndef WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_INTERFACE +#define WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_INTERFACE +/** + * @page page_iface_wp_image_description_creator_params_v1 wp_image_description_creator_params_v1 + * @section page_iface_wp_image_description_creator_params_v1_desc Description + * + * This type of object is used for collecting all the parameters required + * to create a wp_image_description_v1 object. A complete set of required + * parameters consists of these properties: + * - transfer characteristic function (tf) + * - chromaticities of primaries and white point (primary color volume) + * + * The following properties are optional and have a well-defined default + * if not explicitly set: + * - primary color volume luminance range + * - reference white luminance level + * - mastering display primaries and white point (target color volume) + * - mastering luminance range + * + * The following properties are optional and will be ignored + * if not explicitly set: + * - maximum content light level + * - maximum frame-average light level + * + * Each required property must be set exactly once if the client is to create + * an image description. The set requests verify that a property was not + * already set. The create request verifies that all required properties are + * set. There may be several alternative requests for setting each property, + * and in that case the client must choose one of them. + * + * Once all properties have been set, the create request must be used to + * create the image description object, destroying the creator in the + * process. + * + * A viewer, who is viewing the display defined by the resulting image + * description (the viewing environment included), is assumed to be fully + * adapted to the primary color volume's white point. + * + * Any of the following conditions will cause the colorimetry of a pixel + * to become undefined: + * - Values outside of the defined range of the transfer characteristic. + * - Tristimulus that exceeds the target color volume. + * - If extended_target_volume is not supported: tristimulus that exceeds + * the primary color volume. + * + * The closest correspondence to an image description created through this + * interface is the Display class of profiles in ICC. + * @section page_iface_wp_image_description_creator_params_v1_api API + * See @ref iface_wp_image_description_creator_params_v1. + */ +/** + * @defgroup iface_wp_image_description_creator_params_v1 The wp_image_description_creator_params_v1 interface + * + * This type of object is used for collecting all the parameters required + * to create a wp_image_description_v1 object. A complete set of required + * parameters consists of these properties: + * - transfer characteristic function (tf) + * - chromaticities of primaries and white point (primary color volume) + * + * The following properties are optional and have a well-defined default + * if not explicitly set: + * - primary color volume luminance range + * - reference white luminance level + * - mastering display primaries and white point (target color volume) + * - mastering luminance range + * + * The following properties are optional and will be ignored + * if not explicitly set: + * - maximum content light level + * - maximum frame-average light level + * + * Each required property must be set exactly once if the client is to create + * an image description. The set requests verify that a property was not + * already set. The create request verifies that all required properties are + * set. There may be several alternative requests for setting each property, + * and in that case the client must choose one of them. + * + * Once all properties have been set, the create request must be used to + * create the image description object, destroying the creator in the + * process. + * + * A viewer, who is viewing the display defined by the resulting image + * description (the viewing environment included), is assumed to be fully + * adapted to the primary color volume's white point. + * + * Any of the following conditions will cause the colorimetry of a pixel + * to become undefined: + * - Values outside of the defined range of the transfer characteristic. + * - Tristimulus that exceeds the target color volume. + * - If extended_target_volume is not supported: tristimulus that exceeds + * the primary color volume. + * + * The closest correspondence to an image description created through this + * interface is the Display class of profiles in ICC. + */ +extern const struct wl_interface wp_image_description_creator_params_v1_interface; +#endif +#ifndef WP_IMAGE_DESCRIPTION_V1_INTERFACE +#define WP_IMAGE_DESCRIPTION_V1_INTERFACE +/** + * @page page_iface_wp_image_description_v1 wp_image_description_v1 + * @section page_iface_wp_image_description_v1_desc Description + * + * An image description carries information about the pixel color encoding + * and its intended display and viewing environment. The image description is + * attached to a wl_surface via + * wp_color_management_surface_v1.set_image_description. A compositor can use + * this information to decode pixel values into colorimetrically meaningful + * quantities, which allows the compositor to transform the surface contents + * to become suitable for various displays and viewing environments. + * + * Note, that the wp_image_description_v1 object is not ready to be used + * immediately after creation. The object eventually delivers either the + * 'ready' or the 'failed' event, specified in all requests creating it. The + * object is deemed "ready" after receiving the 'ready' event. + * + * An object which is not ready is illegal to use, it can only be destroyed. + * Any other request in this interface shall result in the 'not_ready' + * protocol error. Attempts to use an object which is not ready through other + * interfaces shall raise protocol errors defined there. + * + * Once created and regardless of how it was created, a + * wp_image_description_v1 object always refers to one fixed image + * description. It cannot change after creation. + * @section page_iface_wp_image_description_v1_api API + * See @ref iface_wp_image_description_v1. + */ +/** + * @defgroup iface_wp_image_description_v1 The wp_image_description_v1 interface + * + * An image description carries information about the pixel color encoding + * and its intended display and viewing environment. The image description is + * attached to a wl_surface via + * wp_color_management_surface_v1.set_image_description. A compositor can use + * this information to decode pixel values into colorimetrically meaningful + * quantities, which allows the compositor to transform the surface contents + * to become suitable for various displays and viewing environments. + * + * Note, that the wp_image_description_v1 object is not ready to be used + * immediately after creation. The object eventually delivers either the + * 'ready' or the 'failed' event, specified in all requests creating it. The + * object is deemed "ready" after receiving the 'ready' event. + * + * An object which is not ready is illegal to use, it can only be destroyed. + * Any other request in this interface shall result in the 'not_ready' + * protocol error. Attempts to use an object which is not ready through other + * interfaces shall raise protocol errors defined there. + * + * Once created and regardless of how it was created, a + * wp_image_description_v1 object always refers to one fixed image + * description. It cannot change after creation. + */ +extern const struct wl_interface wp_image_description_v1_interface; +#endif +#ifndef WP_IMAGE_DESCRIPTION_INFO_V1_INTERFACE +#define WP_IMAGE_DESCRIPTION_INFO_V1_INTERFACE +/** + * @page page_iface_wp_image_description_info_v1 wp_image_description_info_v1 + * @section page_iface_wp_image_description_info_v1_desc Description + * + * Sends all matching events describing an image description object exactly + * once and finally sends the 'done' event. + * + * This means + * - if the image description is parametric, it must send + * - primaries + * - named_primaries, if applicable + * - at least one of tf_power and tf_named, as applicable + * - luminances + * - target_primaries + * - target_luminance + * - if the image description is parametric, it may send, if applicable, + * - target_max_cll + * - target_max_fall + * - if the image description contains an ICC profile, it must send the + * icc_file event + * + * Once a wp_image_description_info_v1 object has delivered a 'done' event it + * is automatically destroyed. + * + * Every wp_image_description_info_v1 created from the same + * wp_image_description_v1 shall always return the exact same data. + * @section page_iface_wp_image_description_info_v1_api API + * See @ref iface_wp_image_description_info_v1. + */ +/** + * @defgroup iface_wp_image_description_info_v1 The wp_image_description_info_v1 interface + * + * Sends all matching events describing an image description object exactly + * once and finally sends the 'done' event. + * + * This means + * - if the image description is parametric, it must send + * - primaries + * - named_primaries, if applicable + * - at least one of tf_power and tf_named, as applicable + * - luminances + * - target_primaries + * - target_luminance + * - if the image description is parametric, it may send, if applicable, + * - target_max_cll + * - target_max_fall + * - if the image description contains an ICC profile, it must send the + * icc_file event + * + * Once a wp_image_description_info_v1 object has delivered a 'done' event it + * is automatically destroyed. + * + * Every wp_image_description_info_v1 created from the same + * wp_image_description_v1 shall always return the exact same data. + */ +extern const struct wl_interface wp_image_description_info_v1_interface; +#endif +#ifndef WP_IMAGE_DESCRIPTION_REFERENCE_V1_INTERFACE +#define WP_IMAGE_DESCRIPTION_REFERENCE_V1_INTERFACE +/** + * @page page_iface_wp_image_description_reference_v1 wp_image_description_reference_v1 + * @section page_iface_wp_image_description_reference_v1_desc Description + * + * This object is a reference to an image description. This interface is + * frozen at version 1 to allow other protocols to create + * wp_image_description_v1 objects. + * + * The wp_color_manager_v1.get_image_description request can be used to + * retrieve the underlying image description. + * @section page_iface_wp_image_description_reference_v1_api API + * See @ref iface_wp_image_description_reference_v1. + */ +/** + * @defgroup iface_wp_image_description_reference_v1 The wp_image_description_reference_v1 interface + * + * This object is a reference to an image description. This interface is + * frozen at version 1 to allow other protocols to create + * wp_image_description_v1 objects. + * + * The wp_color_manager_v1.get_image_description request can be used to + * retrieve the underlying image description. + */ +extern const struct wl_interface wp_image_description_reference_v1_interface; +#endif + +#ifndef WP_COLOR_MANAGER_V1_ERROR_ENUM +#define WP_COLOR_MANAGER_V1_ERROR_ENUM +enum wp_color_manager_v1_error { + /** + * request not supported + */ + WP_COLOR_MANAGER_V1_ERROR_UNSUPPORTED_FEATURE = 0, + /** + * color management surface exists already + */ + WP_COLOR_MANAGER_V1_ERROR_SURFACE_EXISTS = 1, +}; +#endif /* WP_COLOR_MANAGER_V1_ERROR_ENUM */ + +#ifndef WP_COLOR_MANAGER_V1_RENDER_INTENT_ENUM +#define WP_COLOR_MANAGER_V1_RENDER_INTENT_ENUM +/** + * @ingroup iface_wp_color_manager_v1 + * rendering intents + * + * See the ICC.1:2022 specification from the International Color Consortium + * for more details about rendering intents. + * + * The principles of ICC defined rendering intents apply with all types of + * image descriptions, not only those with ICC file profiles. + * + * Compositors must support the perceptual rendering intent. Other + * rendering intents are optional. + */ +enum wp_color_manager_v1_render_intent { + /** + * perceptual + */ + WP_COLOR_MANAGER_V1_RENDER_INTENT_PERCEPTUAL = 0, + /** + * media-relative colorimetric + */ + WP_COLOR_MANAGER_V1_RENDER_INTENT_RELATIVE = 1, + /** + * saturation + */ + WP_COLOR_MANAGER_V1_RENDER_INTENT_SATURATION = 2, + /** + * ICC-absolute colorimetric + */ + WP_COLOR_MANAGER_V1_RENDER_INTENT_ABSOLUTE = 3, + /** + * media-relative colorimetric + black point compensation + */ + WP_COLOR_MANAGER_V1_RENDER_INTENT_RELATIVE_BPC = 4, + /** + * ICC-absolute colorimetric without adaptation + * + * This rendering intent is a modified absolute rendering intent + * that assumes the viewer is not adapted to the display white + * point, so no chromatic adaptation between surface and display is + * done. This can be useful for color proofing applications. + * @since 2 + */ + WP_COLOR_MANAGER_V1_RENDER_INTENT_ABSOLUTE_NO_ADAPTATION = 5, +}; +/** + * @ingroup iface_wp_color_manager_v1 + */ +#define WP_COLOR_MANAGER_V1_RENDER_INTENT_ABSOLUTE_NO_ADAPTATION_SINCE_VERSION 2 +#endif /* WP_COLOR_MANAGER_V1_RENDER_INTENT_ENUM */ + +#ifndef WP_COLOR_MANAGER_V1_FEATURE_ENUM +#define WP_COLOR_MANAGER_V1_FEATURE_ENUM +/** + * @ingroup iface_wp_color_manager_v1 + * compositor supported features + */ +enum wp_color_manager_v1_feature { + /** + * create_icc_creator request + */ + WP_COLOR_MANAGER_V1_FEATURE_ICC_V2_V4 = 0, + /** + * create_parametric_creator request + */ + WP_COLOR_MANAGER_V1_FEATURE_PARAMETRIC = 1, + /** + * parametric set_primaries request + */ + WP_COLOR_MANAGER_V1_FEATURE_SET_PRIMARIES = 2, + /** + * parametric set_tf_power request + */ + WP_COLOR_MANAGER_V1_FEATURE_SET_TF_POWER = 3, + /** + * parametric set_luminances request + */ + WP_COLOR_MANAGER_V1_FEATURE_SET_LUMINANCES = 4, + /** + * parametric set_mastering_display_primaries request + * + * The compositor supports set_mastering_display_primaries + * request with a target color volume fully contained inside the + * primary color volume. + */ + WP_COLOR_MANAGER_V1_FEATURE_SET_MASTERING_DISPLAY_PRIMARIES = 5, + /** + * parametric target exceeds primary color volume + * + * The compositor additionally supports target color volumes that + * extend outside of the primary color volume. + * + * This can only be advertised if feature + * set_mastering_display_primaries is supported as well. + */ + WP_COLOR_MANAGER_V1_FEATURE_EXTENDED_TARGET_VOLUME = 6, + /** + * create_windows_scrgb request + */ + WP_COLOR_MANAGER_V1_FEATURE_WINDOWS_SCRGB = 7, +}; +#endif /* WP_COLOR_MANAGER_V1_FEATURE_ENUM */ + +#ifndef WP_COLOR_MANAGER_V1_PRIMARIES_ENUM +#define WP_COLOR_MANAGER_V1_PRIMARIES_ENUM +/** + * @ingroup iface_wp_color_manager_v1 + * named color primaries + * + * Named color primaries used to encode well-known sets of primaries. + * + * A value of 0 is invalid and will never be present in the list of enums. + */ +enum wp_color_manager_v1_primaries { + /** + * Color primaries for the sRGB color space as defined by the BT.709 standard + * + * Color primaries as defined by - Rec. ITU-R BT.709-6 - Rec. + * ITU-R BT.1361-0 conventional colour gamut system and extended + * colour gamut system (historical) - IEC 61966-2-1 sRGB or sYCC - + * IEC 61966-2-4 - Society of Motion Picture and Television + * Engineers (SMPTE) RP 177 (1993) Annex B + */ + WP_COLOR_MANAGER_V1_PRIMARIES_SRGB = 1, + /** + * Color primaries for PAL-M as defined by the BT.470 standard + * + * Color primaries as defined by - Rec. ITU-R BT.470-6 System M + * (historical) - United States National Television System + * Committee 1953 Recommendation for transmission standards for + * color television - United States Federal Communications + * Commission (2003) Title 47 Code of Federal Regulations 73.682 + * (a)(20) + */ + WP_COLOR_MANAGER_V1_PRIMARIES_PAL_M = 2, + /** + * Color primaries for PAL as defined by the BT.601 standard + * + * Color primaries as defined by - Rec. ITU-R BT.470-6 System B, + * G (historical) - Rec. ITU-R BT.601-7 625 - Rec. ITU-R BT.1358-0 + * 625 (historical) - Rec. ITU-R BT.1700-0 625 PAL and 625 SECAM + */ + WP_COLOR_MANAGER_V1_PRIMARIES_PAL = 3, + /** + * Color primaries for NTSC as defined by the BT.601 standard + * + * Color primaries as defined by - Rec. ITU-R BT.601-7 525 - Rec. + * ITU-R BT.1358-1 525 or 625 (historical) - Rec. ITU-R BT.1700-0 + * NTSC - SMPTE 170M (2004) - SMPTE 240M (1999) (historical) + */ + WP_COLOR_MANAGER_V1_PRIMARIES_NTSC = 4, + /** + * Generic film with colour filters using Illuminant C + * + * Color primaries as defined by Recommendation ITU-T H.273 + * "Coding-independent code points for video signal type + * identification" for "generic film". + */ + WP_COLOR_MANAGER_V1_PRIMARIES_GENERIC_FILM = 5, + /** + * Color primaries as defined by the BT.2020 and BT.2100 standard + * + * Color primaries as defined by - Rec. ITU-R BT.2020-2 - Rec. + * ITU-R BT.2100-0 + */ + WP_COLOR_MANAGER_V1_PRIMARIES_BT2020 = 6, + /** + * Color primaries of the full CIE 1931 XYZ color space + * + * Color primaries as defined as the maximum of the CIE 1931 XYZ + * color space by - SMPTE ST 428-1 - (CIE 1931 XYZ as in ISO + * 11664-1) + */ + WP_COLOR_MANAGER_V1_PRIMARIES_CIE1931_XYZ = 7, + /** + * Color primaries of the DCI P3 color space as defined by the SMPTE RP 431 standard + * + * Color primaries as defined by Digital Cinema System and + * published in SMPTE RP 431-2 (2011). + */ + WP_COLOR_MANAGER_V1_PRIMARIES_DCI_P3 = 8, + /** + * Color primaries of Display P3 variant of the DCI-P3 color space as defined by the SMPTE EG 432 standard + * + * Color primaries as defined by Digital Cinema System and + * published in SMPTE EG 432-1 (2010). + */ + WP_COLOR_MANAGER_V1_PRIMARIES_DISPLAY_P3 = 9, + /** + * Color primaries of the Adobe RGB color space as defined by the ISO 12640 standard + * + * Color primaries as defined by Adobe as "Adobe RGB" and later + * published by ISO 12640-4 (2011). + */ + WP_COLOR_MANAGER_V1_PRIMARIES_ADOBE_RGB = 10, +}; +#endif /* WP_COLOR_MANAGER_V1_PRIMARIES_ENUM */ + +#ifndef WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ENUM +#define WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ENUM +/** + * @ingroup iface_wp_color_manager_v1 + * named transfer functions + * + * Named transfer functions used to represent well-known transfer + * characteristics of displays. + * + * A value of 0 is invalid and will never be present in the list of enums. + * + * See appendix.md for the formulae. + */ +enum wp_color_manager_v1_transfer_function { + /** + * BT.1886 display transfer characteristic + * + * Rec. ITU-R BT.1886 is the display transfer characteristic + * assumed by - Rec. ITU-R BT.601-7 525 and 625 - Rec. ITU-R + * BT.709-6 - Rec. ITU-R BT.2020-2 + * + * This TF implies these default luminances from Rec. ITU-R + * BT.2035: - primary color volume minimum: 0.01 cd/m² - primary + * color volume maximum: 100 cd/m² - reference white: 100 cd/m² + */ + WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_BT1886 = 1, + /** + * Assumed display gamma 2.2 transfer function + * + * Transfer characteristics as defined by - Rec. ITU-R BT.470-6 + * System M (historical) - United States National Television System + * Committee 1953 Recommendation for transmission standards for + * color television - United States Federal Communications + * Commission (2003) Title 47 Code of Federal Regulations 73.682 + * (a) (20) - Rec. ITU-R BT.1700-0 625 PAL and 625 SECAM - IEC + * 61966-2-1 (reference display) + */ + WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22 = 2, + /** + * Assumed display gamma 2.8 transfer function + * + * Transfer characteristics as defined by - Rec. ITU-R BT.470-6 + * System B, G (historical) + */ + WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA28 = 3, + /** + * SMPTE ST 240 transfer function + * + * Transfer characteristics as defined by - SMPTE ST 240 (1999) + */ + WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST240 = 4, + /** + * extended linear transfer function + * + * Linear transfer function defined over all real numbers. + * Normalised electrical values are equal the normalised optical + * values. + */ + WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR = 5, + /** + * logarithmic 100:1 transfer function + * + * Logarithmic transfer characteristic (100:1 range). + */ + WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_LOG_100 = 6, + /** + * logarithmic (100*Sqrt(10) : 1) transfer function + * + * Logarithmic transfer characteristic (100 * Sqrt(10) : 1 + * range). + */ + WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_LOG_316 = 7, + /** + * IEC 61966-2-4 transfer function + * + * Transfer characteristics as defined by - IEC 61966-2-4 + */ + WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_XVYCC = 8, + /** + * Deprecated (ambiguous sRGB transfer function) + * + * Transfer characteristics as defined by - IEC 61966-2-1 sRGB + * + * As a rule of thumb, use gamma22 for video, motion picture and + * computer graphics, or compound_power_2_4 for ICC calibrated + * print workflows. + * @deprecated Deprecated since version 2 + */ + WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB = 9, + /** + * Deprecated (Extended sRGB piece-wise transfer function) + * + * Transfer characteristics as defined by - IEC 61966-2-1 sYCC + * @deprecated Deprecated since version 2 + */ + WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_SRGB = 10, + /** + * perceptual quantizer transfer function + * + * Transfer characteristics as defined by - SMPTE ST 2084 (2014) + * for 10-, 12-, 14- and 16-bit systems - Rec. ITU-R BT.2100-2 + * perceptual quantization (PQ) system + * + * This TF implies these default luminances - primary color volume + * minimum: 0.005 cd/m² - primary color volume maximum: 10000 + * cd/m² - reference white: 203 cd/m² + * + * The difference between the primary color volume minimum and + * maximum must be approximately 10000 cd/m² as that is the swing + * of the EOTF defined by ST 2084 and BT.2100. The default value + * for the reference white is a protocol addition: it is suggested + * by Report ITU-R BT.2408-7 and is not part of ST 2084 or BT.2100. + */ + WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ = 11, + /** + * SMPTE ST 428 transfer function + * + * Transfer characteristics as defined by - SMPTE ST 428-1 (2019) + */ + WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST428 = 12, + /** + * hybrid log-gamma transfer function + * + * Transfer characteristics as defined by - ARIB STD-B67 (2015) - + * Rec. ITU-R BT.2100-2 hybrid log-gamma (HLG) system + * + * This TF implies these default luminances - primary color volume + * minimum: 0.005 cd/m² - primary color volume maximum: 1000 + * cd/m² - reference white: 203 cd/m² + * + * HLG is a relative display-referred signal with a specified + * non-linear mapping to the display peak luminance (the HLG OOTF). + * All absolute luminance values used here for HLG assume a 1000 + * cd/m² peak display. + * + * The default value for the reference white is a protocol + * addition: it is suggested by Report ITU-R BT.2408-7 and is not + * part of ARIB STD-B67 or BT.2100. + */ + WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_HLG = 13, + /** + * IEC 61966-2-1 encoding function + * + * Encoding characteristics as defined by IEC 61966-2-1, for + * displays that invert the encoding function. + * @since 2 + */ + WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_COMPOUND_POWER_2_4 = 14, +}; +/** + * @ingroup iface_wp_color_manager_v1 + */ +#define WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_COMPOUND_POWER_2_4_SINCE_VERSION 2 +#endif /* WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ENUM */ + +/** + * @ingroup iface_wp_color_manager_v1 + * @struct wp_color_manager_v1_listener + */ +struct wp_color_manager_v1_listener { + /** + * supported rendering intent + * + * When this object is created, it shall immediately send this + * event once for each rendering intent the compositor supports. + * + * A compositor must not advertise intents that are deprecated in + * the bound version of the interface. + * @param render_intent rendering intent + */ + void (*supported_intent)(void *data, + struct wp_color_manager_v1 *wp_color_manager_v1, + uint32_t render_intent); + /** + * supported features + * + * When this object is created, it shall immediately send this + * event once for each compositor supported feature listed in the + * enumeration. + * + * A compositor must not advertise features that are deprecated in + * the bound version of the interface. + * @param feature supported feature + */ + void (*supported_feature)(void *data, + struct wp_color_manager_v1 *wp_color_manager_v1, + uint32_t feature); + /** + * supported named transfer characteristic + * + * When this object is created, it shall immediately send this + * event once for each named transfer function the compositor + * supports with the parametric image description creator. + * + * A compositor must not advertise transfer functions that are + * deprecated in the bound version of the interface. + * @param tf Named transfer function + */ + void (*supported_tf_named)(void *data, + struct wp_color_manager_v1 *wp_color_manager_v1, + uint32_t tf); + /** + * supported named primaries + * + * When this object is created, it shall immediately send this + * event once for each named set of primaries the compositor + * supports with the parametric image description creator. + * + * A compositor must not advertise names that are deprecated in the + * bound version of the interface. + * @param primaries Named color primaries + */ + void (*supported_primaries_named)(void *data, + struct wp_color_manager_v1 *wp_color_manager_v1, + uint32_t primaries); + /** + * all features have been sent + * + * This event is sent when all supported rendering intents, + * features, transfer functions and named primaries have been sent. + */ + void (*done)(void *data, + struct wp_color_manager_v1 *wp_color_manager_v1); +}; + +/** + * @ingroup iface_wp_color_manager_v1 + */ +static inline int +wp_color_manager_v1_add_listener(struct wp_color_manager_v1 *wp_color_manager_v1, + const struct wp_color_manager_v1_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wp_color_manager_v1, + (void (**)(void)) listener, data); +} + +#define WP_COLOR_MANAGER_V1_DESTROY 0 +#define WP_COLOR_MANAGER_V1_GET_OUTPUT 1 +#define WP_COLOR_MANAGER_V1_GET_SURFACE 2 +#define WP_COLOR_MANAGER_V1_GET_SURFACE_FEEDBACK 3 +#define WP_COLOR_MANAGER_V1_CREATE_ICC_CREATOR 4 +#define WP_COLOR_MANAGER_V1_CREATE_PARAMETRIC_CREATOR 5 +#define WP_COLOR_MANAGER_V1_CREATE_WINDOWS_SCRGB 6 +#define WP_COLOR_MANAGER_V1_GET_IMAGE_DESCRIPTION 7 + +/** + * @ingroup iface_wp_color_manager_v1 + */ +#define WP_COLOR_MANAGER_V1_SUPPORTED_INTENT_SINCE_VERSION 1 +/** + * @ingroup iface_wp_color_manager_v1 + */ +#define WP_COLOR_MANAGER_V1_SUPPORTED_FEATURE_SINCE_VERSION 1 +/** + * @ingroup iface_wp_color_manager_v1 + */ +#define WP_COLOR_MANAGER_V1_SUPPORTED_TF_NAMED_SINCE_VERSION 1 +/** + * @ingroup iface_wp_color_manager_v1 + */ +#define WP_COLOR_MANAGER_V1_SUPPORTED_PRIMARIES_NAMED_SINCE_VERSION 1 +/** + * @ingroup iface_wp_color_manager_v1 + */ +#define WP_COLOR_MANAGER_V1_DONE_SINCE_VERSION 1 + +/** + * @ingroup iface_wp_color_manager_v1 + */ +#define WP_COLOR_MANAGER_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wp_color_manager_v1 + */ +#define WP_COLOR_MANAGER_V1_GET_OUTPUT_SINCE_VERSION 1 +/** + * @ingroup iface_wp_color_manager_v1 + */ +#define WP_COLOR_MANAGER_V1_GET_SURFACE_SINCE_VERSION 1 +/** + * @ingroup iface_wp_color_manager_v1 + */ +#define WP_COLOR_MANAGER_V1_GET_SURFACE_FEEDBACK_SINCE_VERSION 1 +/** + * @ingroup iface_wp_color_manager_v1 + */ +#define WP_COLOR_MANAGER_V1_CREATE_ICC_CREATOR_SINCE_VERSION 1 +/** + * @ingroup iface_wp_color_manager_v1 + */ +#define WP_COLOR_MANAGER_V1_CREATE_PARAMETRIC_CREATOR_SINCE_VERSION 1 +/** + * @ingroup iface_wp_color_manager_v1 + */ +#define WP_COLOR_MANAGER_V1_CREATE_WINDOWS_SCRGB_SINCE_VERSION 1 +/** + * @ingroup iface_wp_color_manager_v1 + */ +#define WP_COLOR_MANAGER_V1_GET_IMAGE_DESCRIPTION_SINCE_VERSION 2 + +/** @ingroup iface_wp_color_manager_v1 */ +static inline void +wp_color_manager_v1_set_user_data(struct wp_color_manager_v1 *wp_color_manager_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_color_manager_v1, user_data); +} + +/** @ingroup iface_wp_color_manager_v1 */ +static inline void * +wp_color_manager_v1_get_user_data(struct wp_color_manager_v1 *wp_color_manager_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_color_manager_v1); +} + +static inline uint32_t +wp_color_manager_v1_get_version(struct wp_color_manager_v1 *wp_color_manager_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_color_manager_v1); +} + +/** + * @ingroup iface_wp_color_manager_v1 + * + * Destroy the wp_color_manager_v1 object. This does not affect any other + * objects in any way. + */ +static inline void +wp_color_manager_v1_destroy(struct wp_color_manager_v1 *wp_color_manager_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_color_manager_v1, + WP_COLOR_MANAGER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_color_manager_v1), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_wp_color_manager_v1 + * + * This creates a new wp_color_management_output_v1 object for the + * given wl_output. + * + * See the wp_color_management_output_v1 interface for more details. + */ +static inline struct wp_color_management_output_v1 * +wp_color_manager_v1_get_output(struct wp_color_manager_v1 *wp_color_manager_v1, struct wl_output *output) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) wp_color_manager_v1, + WP_COLOR_MANAGER_V1_GET_OUTPUT, &wp_color_management_output_v1_interface, wl_proxy_get_version((struct wl_proxy *) wp_color_manager_v1), 0, NULL, output); + + return (struct wp_color_management_output_v1 *) id; +} + +/** + * @ingroup iface_wp_color_manager_v1 + * + * If a wp_color_management_surface_v1 object already exists for the given + * wl_surface, the protocol error surface_exists is raised. + * + * This creates a new color wp_color_management_surface_v1 object for the + * given wl_surface. + * + * See the wp_color_management_surface_v1 interface for more details. + */ +static inline struct wp_color_management_surface_v1 * +wp_color_manager_v1_get_surface(struct wp_color_manager_v1 *wp_color_manager_v1, struct wl_surface *surface) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) wp_color_manager_v1, + WP_COLOR_MANAGER_V1_GET_SURFACE, &wp_color_management_surface_v1_interface, wl_proxy_get_version((struct wl_proxy *) wp_color_manager_v1), 0, NULL, surface); + + return (struct wp_color_management_surface_v1 *) id; +} + +/** + * @ingroup iface_wp_color_manager_v1 + * + * This creates a new color wp_color_management_surface_feedback_v1 object + * for the given wl_surface. + * + * See the wp_color_management_surface_feedback_v1 interface for more + * details. + */ +static inline struct wp_color_management_surface_feedback_v1 * +wp_color_manager_v1_get_surface_feedback(struct wp_color_manager_v1 *wp_color_manager_v1, struct wl_surface *surface) +{ + struct wl_proxy *id; + + id = wl_proxy_marshal_flags((struct wl_proxy *) wp_color_manager_v1, + WP_COLOR_MANAGER_V1_GET_SURFACE_FEEDBACK, &wp_color_management_surface_feedback_v1_interface, wl_proxy_get_version((struct wl_proxy *) wp_color_manager_v1), 0, NULL, surface); + + return (struct wp_color_management_surface_feedback_v1 *) id; +} + +/** + * @ingroup iface_wp_color_manager_v1 + * + * Makes a new ICC-based image description creator object with all + * properties initially unset. The client can then use the object's + * interface to define all the required properties for an image description + * and finally create a wp_image_description_v1 object. + * + * This request can be used when the compositor advertises + * wp_color_manager_v1.feature.icc_v2_v4. + * Otherwise this request raises the protocol error unsupported_feature. + */ +static inline struct wp_image_description_creator_icc_v1 * +wp_color_manager_v1_create_icc_creator(struct wp_color_manager_v1 *wp_color_manager_v1) +{ + struct wl_proxy *obj; + + obj = wl_proxy_marshal_flags((struct wl_proxy *) wp_color_manager_v1, + WP_COLOR_MANAGER_V1_CREATE_ICC_CREATOR, &wp_image_description_creator_icc_v1_interface, wl_proxy_get_version((struct wl_proxy *) wp_color_manager_v1), 0, NULL); + + return (struct wp_image_description_creator_icc_v1 *) obj; +} + +/** + * @ingroup iface_wp_color_manager_v1 + * + * Makes a new parametric image description creator object with all + * properties initially unset. The client can then use the object's + * interface to define all the required properties for an image description + * and finally create a wp_image_description_v1 object. + * + * This request can be used when the compositor advertises + * wp_color_manager_v1.feature.parametric. + * Otherwise this request raises the protocol error unsupported_feature. + */ +static inline struct wp_image_description_creator_params_v1 * +wp_color_manager_v1_create_parametric_creator(struct wp_color_manager_v1 *wp_color_manager_v1) +{ + struct wl_proxy *obj; + + obj = wl_proxy_marshal_flags((struct wl_proxy *) wp_color_manager_v1, + WP_COLOR_MANAGER_V1_CREATE_PARAMETRIC_CREATOR, &wp_image_description_creator_params_v1_interface, wl_proxy_get_version((struct wl_proxy *) wp_color_manager_v1), 0, NULL); + + return (struct wp_image_description_creator_params_v1 *) obj; +} + +/** + * @ingroup iface_wp_color_manager_v1 + * + * This creates a pre-defined image description for the so-called + * Windows-scRGB stimulus encoding. This comes from the Windows 10 handling + * of its own definition of an scRGB color space for an HDR screen + * driven in BT.2100/PQ signalling mode. + * + * Windows-scRGB uses sRGB (BT.709) color primaries and white point. + * The transfer characteristic is extended linear. + * + * The nominal color channel value range is extended, meaning it includes + * negative and greater than 1.0 values. Negative values are used to + * escape the sRGB color gamut boundaries. To make use of the extended + * range, the client needs to use a pixel format that can represent those + * values, e.g. floating-point 16 bits per channel. + * + * Nominal color value R=G=B=0.0 corresponds to BT.2100/PQ system + * 0 cd/m², and R=G=B=1.0 corresponds to BT.2100/PQ system 80 cd/m². + * The maximum is R=G=B=125.0 corresponding to 10k cd/m². + * + * Windows-scRGB is displayed by Windows 10 by converting it to + * BT.2100/PQ, maintaining the CIE 1931 chromaticity and mapping the + * luminance as above. No adjustment is made to the signal to account + * for the viewing conditions. + * + * The reference white level of Windows-scRGB is unknown. If a + * reference white level must be assumed for compositor processing, it + * should be R=G=B=2.5375 corresponding to 203 cd/m² of Report ITU-R + * BT.2408-7. + * + * The target color volume of Windows-scRGB is unknown. The color gamut + * may be anything between sRGB and BT.2100. + * + * Note: EGL_EXT_gl_colorspace_scrgb_linear definition differs from + * Windows-scRGB by using R=G=B=1.0 as the reference white level, while + * Windows-scRGB reference white level is unknown or varies. However, + * it seems probable that Windows implements both + * EGL_EXT_gl_colorspace_scrgb_linear and Vulkan + * VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT as Windows-scRGB. + * + * This request can be used when the compositor advertises + * wp_color_manager_v1.feature.windows_scrgb. + * Otherwise this request raises the protocol error unsupported_feature. + * + * The resulting image description object does not allow get_information + * request. The wp_image_description_v1.ready event shall be sent. + */ +static inline struct wp_image_description_v1 * +wp_color_manager_v1_create_windows_scrgb(struct wp_color_manager_v1 *wp_color_manager_v1) +{ + struct wl_proxy *image_description; + + image_description = wl_proxy_marshal_flags((struct wl_proxy *) wp_color_manager_v1, + WP_COLOR_MANAGER_V1_CREATE_WINDOWS_SCRGB, &wp_image_description_v1_interface, wl_proxy_get_version((struct wl_proxy *) wp_color_manager_v1), 0, NULL); + + return (struct wp_image_description_v1 *) image_description; +} + +/** + * @ingroup iface_wp_color_manager_v1 + * + * This request retrieves the image description backing a reference. + * + * The get_information request can be used if and only if the request that + * creates the reference allows it. + */ +static inline struct wp_image_description_v1 * +wp_color_manager_v1_get_image_description(struct wp_color_manager_v1 *wp_color_manager_v1, struct wp_image_description_reference_v1 *reference) +{ + struct wl_proxy *image_description; + + image_description = wl_proxy_marshal_flags((struct wl_proxy *) wp_color_manager_v1, + WP_COLOR_MANAGER_V1_GET_IMAGE_DESCRIPTION, &wp_image_description_v1_interface, wl_proxy_get_version((struct wl_proxy *) wp_color_manager_v1), 0, NULL, reference); + + return (struct wp_image_description_v1 *) image_description; +} + +/** + * @ingroup iface_wp_color_management_output_v1 + * @struct wp_color_management_output_v1_listener + */ +struct wp_color_management_output_v1_listener { + /** + * image description changed + * + * This event is sent whenever the image description of the + * output changed, followed by one wl_output.done event common to + * output events across all extensions. + * + * If the client wants to use the updated image description, it + * needs to do get_image_description again, because image + * description objects are immutable. + */ + void (*image_description_changed)(void *data, + struct wp_color_management_output_v1 *wp_color_management_output_v1); +}; + +/** + * @ingroup iface_wp_color_management_output_v1 + */ +static inline int +wp_color_management_output_v1_add_listener(struct wp_color_management_output_v1 *wp_color_management_output_v1, + const struct wp_color_management_output_v1_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wp_color_management_output_v1, + (void (**)(void)) listener, data); +} + +#define WP_COLOR_MANAGEMENT_OUTPUT_V1_DESTROY 0 +#define WP_COLOR_MANAGEMENT_OUTPUT_V1_GET_IMAGE_DESCRIPTION 1 + +/** + * @ingroup iface_wp_color_management_output_v1 + */ +#define WP_COLOR_MANAGEMENT_OUTPUT_V1_IMAGE_DESCRIPTION_CHANGED_SINCE_VERSION 1 + +/** + * @ingroup iface_wp_color_management_output_v1 + */ +#define WP_COLOR_MANAGEMENT_OUTPUT_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wp_color_management_output_v1 + */ +#define WP_COLOR_MANAGEMENT_OUTPUT_V1_GET_IMAGE_DESCRIPTION_SINCE_VERSION 1 + +/** @ingroup iface_wp_color_management_output_v1 */ +static inline void +wp_color_management_output_v1_set_user_data(struct wp_color_management_output_v1 *wp_color_management_output_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_color_management_output_v1, user_data); +} + +/** @ingroup iface_wp_color_management_output_v1 */ +static inline void * +wp_color_management_output_v1_get_user_data(struct wp_color_management_output_v1 *wp_color_management_output_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_color_management_output_v1); +} + +static inline uint32_t +wp_color_management_output_v1_get_version(struct wp_color_management_output_v1 *wp_color_management_output_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_color_management_output_v1); +} + +/** + * @ingroup iface_wp_color_management_output_v1 + * + * Destroy the color wp_color_management_output_v1 object. This does not + * affect any remaining protocol objects. + */ +static inline void +wp_color_management_output_v1_destroy(struct wp_color_management_output_v1 *wp_color_management_output_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_color_management_output_v1, + WP_COLOR_MANAGEMENT_OUTPUT_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_color_management_output_v1), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_wp_color_management_output_v1 + * + * This creates a new wp_image_description_v1 object for the current image + * description of the output. There always is exactly one image description + * active for an output so the client should destroy the image description + * created by earlier invocations of this request. This request is usually + * sent as a reaction to the image_description_changed event or when + * creating a wp_color_management_output_v1 object. + * + * The image description of an output represents the color encoding the + * output expects. There might be performance and power advantages, as well + * as improved color reproduction, if a content update matches the image + * description of the output it is being shown on. If a content update is + * shown on any other output than the one it matches the image description + * of, then the color reproduction on those outputs might be considerably + * worse. + * + * The created wp_image_description_v1 object preserves the image + * description of the output from the time the object was created. + * + * The resulting image description object allows get_information request. + * + * If this protocol object is inert, the resulting image description object + * shall immediately deliver the wp_image_description_v1.failed event with + * the no_output cause. + * + * If the interface version is inadequate for the output's image + * description, meaning that the client does not support all the events + * needed to deliver the crucial information, the resulting image + * description object shall immediately deliver the + * wp_image_description_v1.failed event with the low_version cause. + * + * Otherwise the object shall immediately deliver the ready event. + */ +static inline struct wp_image_description_v1 * +wp_color_management_output_v1_get_image_description(struct wp_color_management_output_v1 *wp_color_management_output_v1) +{ + struct wl_proxy *image_description; + + image_description = wl_proxy_marshal_flags((struct wl_proxy *) wp_color_management_output_v1, + WP_COLOR_MANAGEMENT_OUTPUT_V1_GET_IMAGE_DESCRIPTION, &wp_image_description_v1_interface, wl_proxy_get_version((struct wl_proxy *) wp_color_management_output_v1), 0, NULL); + + return (struct wp_image_description_v1 *) image_description; +} + +#ifndef WP_COLOR_MANAGEMENT_SURFACE_V1_ERROR_ENUM +#define WP_COLOR_MANAGEMENT_SURFACE_V1_ERROR_ENUM +/** + * @ingroup iface_wp_color_management_surface_v1 + * protocol errors + */ +enum wp_color_management_surface_v1_error { + /** + * unsupported rendering intent + */ + WP_COLOR_MANAGEMENT_SURFACE_V1_ERROR_RENDER_INTENT = 0, + /** + * invalid image description + */ + WP_COLOR_MANAGEMENT_SURFACE_V1_ERROR_IMAGE_DESCRIPTION = 1, + /** + * forbidden request on inert object + */ + WP_COLOR_MANAGEMENT_SURFACE_V1_ERROR_INERT = 2, +}; +#endif /* WP_COLOR_MANAGEMENT_SURFACE_V1_ERROR_ENUM */ + +#define WP_COLOR_MANAGEMENT_SURFACE_V1_DESTROY 0 +#define WP_COLOR_MANAGEMENT_SURFACE_V1_SET_IMAGE_DESCRIPTION 1 +#define WP_COLOR_MANAGEMENT_SURFACE_V1_UNSET_IMAGE_DESCRIPTION 2 + + +/** + * @ingroup iface_wp_color_management_surface_v1 + */ +#define WP_COLOR_MANAGEMENT_SURFACE_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wp_color_management_surface_v1 + */ +#define WP_COLOR_MANAGEMENT_SURFACE_V1_SET_IMAGE_DESCRIPTION_SINCE_VERSION 1 +/** + * @ingroup iface_wp_color_management_surface_v1 + */ +#define WP_COLOR_MANAGEMENT_SURFACE_V1_UNSET_IMAGE_DESCRIPTION_SINCE_VERSION 1 + +/** @ingroup iface_wp_color_management_surface_v1 */ +static inline void +wp_color_management_surface_v1_set_user_data(struct wp_color_management_surface_v1 *wp_color_management_surface_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_color_management_surface_v1, user_data); +} + +/** @ingroup iface_wp_color_management_surface_v1 */ +static inline void * +wp_color_management_surface_v1_get_user_data(struct wp_color_management_surface_v1 *wp_color_management_surface_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_color_management_surface_v1); +} + +static inline uint32_t +wp_color_management_surface_v1_get_version(struct wp_color_management_surface_v1 *wp_color_management_surface_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_color_management_surface_v1); +} + +/** + * @ingroup iface_wp_color_management_surface_v1 + * + * Destroy the wp_color_management_surface_v1 object and do the same as + * unset_image_description. + */ +static inline void +wp_color_management_surface_v1_destroy(struct wp_color_management_surface_v1 *wp_color_management_surface_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_color_management_surface_v1, + WP_COLOR_MANAGEMENT_SURFACE_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_color_management_surface_v1), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_wp_color_management_surface_v1 + * + * If this protocol object is inert, the protocol error inert is raised. + * + * Set the image description of the underlying surface. The image + * description and rendering intent are double-buffered state, see + * wl_surface.commit. + * + * It is the client's responsibility to understand the image description + * it sets on a surface, and to provide content that matches that image + * description. Compositors might convert images to match their own or any + * other image descriptions. + * + * Image descriptions which are not ready (see wp_image_description_v1) + * are forbidden in this request, and in such case the protocol error + * image_description is raised. + * + * All image descriptions which are ready (see wp_image_description_v1) + * are allowed and must always be accepted by the compositor. + * + * When an image description is set on a surface, it establishes an + * explicit link between surface pixel values and surface colorimetry. + * This link may be undefined for some pixel values, see the image + * description creator interfaces for the conditions. Non-finite + * floating-point values (NaN, Inf) always have an undefined colorimetry. + * + * A rendering intent provides the client's preference on how surface + * colorimetry should be mapped to each output. The render_intent value + * must be one advertised by the compositor with + * wp_color_manager_v1.render_intent event, otherwise the protocol error + * render_intent is raised. + * + * By default, a surface does not have an associated image description + * nor a rendering intent. The handling of color on such surfaces is + * compositor implementation defined. Compositors should handle such + * surfaces as sRGB, but may handle them differently if they have specific + * requirements. + * + * Setting the image description has copy semantics; after this request, + * the image description can be immediately destroyed without affecting + * the pending state of the surface. + */ +static inline void +wp_color_management_surface_v1_set_image_description(struct wp_color_management_surface_v1 *wp_color_management_surface_v1, struct wp_image_description_v1 *image_description, uint32_t render_intent) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_color_management_surface_v1, + WP_COLOR_MANAGEMENT_SURFACE_V1_SET_IMAGE_DESCRIPTION, NULL, wl_proxy_get_version((struct wl_proxy *) wp_color_management_surface_v1), 0, image_description, render_intent); +} + +/** + * @ingroup iface_wp_color_management_surface_v1 + * + * If this protocol object is inert, the protocol error inert is raised. + * + * This request removes any image description from the surface. See + * set_image_description for how a compositor handles a surface without + * an image description. This is double-buffered state, see + * wl_surface.commit. + */ +static inline void +wp_color_management_surface_v1_unset_image_description(struct wp_color_management_surface_v1 *wp_color_management_surface_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_color_management_surface_v1, + WP_COLOR_MANAGEMENT_SURFACE_V1_UNSET_IMAGE_DESCRIPTION, NULL, wl_proxy_get_version((struct wl_proxy *) wp_color_management_surface_v1), 0); +} + +#ifndef WP_COLOR_MANAGEMENT_SURFACE_FEEDBACK_V1_ERROR_ENUM +#define WP_COLOR_MANAGEMENT_SURFACE_FEEDBACK_V1_ERROR_ENUM +/** + * @ingroup iface_wp_color_management_surface_feedback_v1 + * protocol errors + */ +enum wp_color_management_surface_feedback_v1_error { + /** + * forbidden request on inert object + */ + WP_COLOR_MANAGEMENT_SURFACE_FEEDBACK_V1_ERROR_INERT = 0, + /** + * attempted to use an unsupported feature + */ + WP_COLOR_MANAGEMENT_SURFACE_FEEDBACK_V1_ERROR_UNSUPPORTED_FEATURE = 1, +}; +#endif /* WP_COLOR_MANAGEMENT_SURFACE_FEEDBACK_V1_ERROR_ENUM */ + +/** + * @ingroup iface_wp_color_management_surface_feedback_v1 + * @struct wp_color_management_surface_feedback_v1_listener + */ +struct wp_color_management_surface_feedback_v1_listener { + /** + * the preferred image description changed (32-bit) + * + * Starting from interface version 2, 'preferred_changed2' is + * sent instead of this event. See the 'preferred_changed2' event + * for the definition. + * @param identity the 32-bit image description id number + * @deprecated Deprecated since version 2 + */ + void (*preferred_changed)(void *data, + struct wp_color_management_surface_feedback_v1 *wp_color_management_surface_feedback_v1, + uint32_t identity); + /** + * the preferred image description changed + * + * The preferred image description is the one which likely has + * the most performance and/or quality benefits for the compositor + * if used by the client for its wl_surface contents. This event is + * sent whenever the compositor changes the wl_surface's preferred + * image description. + * + * This event sends the identity of the new preferred state as the + * argument, so clients who are aware of the image description + * already can reuse it. Otherwise, if the client client wants to + * know what the preferred image description is, it shall use the + * get_preferred request. + * + * The preferred image description is not automatically used for + * anything. It is only a hint, and clients may set any valid image + * description with set_image_description, but there might be + * performance and color accuracy improvements by providing the + * wl_surface contents in the preferred image description. + * Therefore clients that can, should render according to the + * preferred image description + * @param identity_hi high 32 bits of the 64-bit image description id number + * @param identity_lo low 32 bits of the 64-bit image description id number + * @since 2 + */ + void (*preferred_changed2)(void *data, + struct wp_color_management_surface_feedback_v1 *wp_color_management_surface_feedback_v1, + uint32_t identity_hi, + uint32_t identity_lo); +}; + +/** + * @ingroup iface_wp_color_management_surface_feedback_v1 + */ +static inline int +wp_color_management_surface_feedback_v1_add_listener(struct wp_color_management_surface_feedback_v1 *wp_color_management_surface_feedback_v1, + const struct wp_color_management_surface_feedback_v1_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wp_color_management_surface_feedback_v1, + (void (**)(void)) listener, data); +} + +#define WP_COLOR_MANAGEMENT_SURFACE_FEEDBACK_V1_DESTROY 0 +#define WP_COLOR_MANAGEMENT_SURFACE_FEEDBACK_V1_GET_PREFERRED 1 +#define WP_COLOR_MANAGEMENT_SURFACE_FEEDBACK_V1_GET_PREFERRED_PARAMETRIC 2 + +/** + * @ingroup iface_wp_color_management_surface_feedback_v1 + */ +#define WP_COLOR_MANAGEMENT_SURFACE_FEEDBACK_V1_PREFERRED_CHANGED_SINCE_VERSION 1 +/** + * @ingroup iface_wp_color_management_surface_feedback_v1 + */ +#define WP_COLOR_MANAGEMENT_SURFACE_FEEDBACK_V1_PREFERRED_CHANGED2_SINCE_VERSION 2 + +/** + * @ingroup iface_wp_color_management_surface_feedback_v1 + */ +#define WP_COLOR_MANAGEMENT_SURFACE_FEEDBACK_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wp_color_management_surface_feedback_v1 + */ +#define WP_COLOR_MANAGEMENT_SURFACE_FEEDBACK_V1_GET_PREFERRED_SINCE_VERSION 1 +/** + * @ingroup iface_wp_color_management_surface_feedback_v1 + */ +#define WP_COLOR_MANAGEMENT_SURFACE_FEEDBACK_V1_GET_PREFERRED_PARAMETRIC_SINCE_VERSION 1 + +/** @ingroup iface_wp_color_management_surface_feedback_v1 */ +static inline void +wp_color_management_surface_feedback_v1_set_user_data(struct wp_color_management_surface_feedback_v1 *wp_color_management_surface_feedback_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_color_management_surface_feedback_v1, user_data); +} + +/** @ingroup iface_wp_color_management_surface_feedback_v1 */ +static inline void * +wp_color_management_surface_feedback_v1_get_user_data(struct wp_color_management_surface_feedback_v1 *wp_color_management_surface_feedback_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_color_management_surface_feedback_v1); +} + +static inline uint32_t +wp_color_management_surface_feedback_v1_get_version(struct wp_color_management_surface_feedback_v1 *wp_color_management_surface_feedback_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_color_management_surface_feedback_v1); +} + +/** + * @ingroup iface_wp_color_management_surface_feedback_v1 + * + * Destroy the wp_color_management_surface_feedback_v1 object. + */ +static inline void +wp_color_management_surface_feedback_v1_destroy(struct wp_color_management_surface_feedback_v1 *wp_color_management_surface_feedback_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_color_management_surface_feedback_v1, + WP_COLOR_MANAGEMENT_SURFACE_FEEDBACK_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_color_management_surface_feedback_v1), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_wp_color_management_surface_feedback_v1 + * + * If this protocol object is inert, the protocol error inert is raised. + * + * The preferred image description represents the compositor's preferred + * color encoding for this wl_surface at the current time. There might be + * performance and power advantages, as well as improved color + * reproduction, if the image description of a content update matches the + * preferred image description. + * + * This creates a new wp_image_description_v1 object for the currently + * preferred image description for the wl_surface. The client should + * stop using and destroy the image descriptions created by earlier + * invocations of this request for the associated wl_surface. + * This request is usually sent as a reaction to the preferred_changed + * event or when creating a wp_color_management_surface_feedback_v1 object + * if the client is capable of adapting to image descriptions. + * + * The created wp_image_description_v1 object preserves the preferred image + * description of the wl_surface from the time the object was created. + * + * The resulting image description object allows get_information request. + * + * If the image description is parametric, the client should set it on its + * wl_surface only if the image description is an exact match with the + * client content. Particularly if everything else matches, but the target + * color volume is greater than what the client needs, the client should + * create its own parameric image description with its exact parameters. + * + * If the interface version is inadequate for the preferred image + * description, meaning that the client does not support all the + * events needed to deliver the crucial information, the resulting image + * description object shall immediately deliver the + * wp_image_description_v1.failed event with the low_version cause, + * otherwise the object shall immediately deliver the ready event. + */ +static inline struct wp_image_description_v1 * +wp_color_management_surface_feedback_v1_get_preferred(struct wp_color_management_surface_feedback_v1 *wp_color_management_surface_feedback_v1) +{ + struct wl_proxy *image_description; + + image_description = wl_proxy_marshal_flags((struct wl_proxy *) wp_color_management_surface_feedback_v1, + WP_COLOR_MANAGEMENT_SURFACE_FEEDBACK_V1_GET_PREFERRED, &wp_image_description_v1_interface, wl_proxy_get_version((struct wl_proxy *) wp_color_management_surface_feedback_v1), 0, NULL); + + return (struct wp_image_description_v1 *) image_description; +} + +/** + * @ingroup iface_wp_color_management_surface_feedback_v1 + * + * The same description as for get_preferred applies, except the returned + * image description is guaranteed to be parametric. This is meant for + * clients that can only deal with parametric image descriptions. + * + * If the compositor doesn't support parametric image descriptions, the + * unsupported_feature error is emitted. + */ +static inline struct wp_image_description_v1 * +wp_color_management_surface_feedback_v1_get_preferred_parametric(struct wp_color_management_surface_feedback_v1 *wp_color_management_surface_feedback_v1) +{ + struct wl_proxy *image_description; + + image_description = wl_proxy_marshal_flags((struct wl_proxy *) wp_color_management_surface_feedback_v1, + WP_COLOR_MANAGEMENT_SURFACE_FEEDBACK_V1_GET_PREFERRED_PARAMETRIC, &wp_image_description_v1_interface, wl_proxy_get_version((struct wl_proxy *) wp_color_management_surface_feedback_v1), 0, NULL); + + return (struct wp_image_description_v1 *) image_description; +} + +#ifndef WP_IMAGE_DESCRIPTION_CREATOR_ICC_V1_ERROR_ENUM +#define WP_IMAGE_DESCRIPTION_CREATOR_ICC_V1_ERROR_ENUM +/** + * @ingroup iface_wp_image_description_creator_icc_v1 + * protocol errors + */ +enum wp_image_description_creator_icc_v1_error { + /** + * incomplete parameter set + */ + WP_IMAGE_DESCRIPTION_CREATOR_ICC_V1_ERROR_INCOMPLETE_SET = 0, + /** + * property already set + */ + WP_IMAGE_DESCRIPTION_CREATOR_ICC_V1_ERROR_ALREADY_SET = 1, + /** + * fd not seekable and readable + */ + WP_IMAGE_DESCRIPTION_CREATOR_ICC_V1_ERROR_BAD_FD = 2, + /** + * no or too much data + */ + WP_IMAGE_DESCRIPTION_CREATOR_ICC_V1_ERROR_BAD_SIZE = 3, + /** + * offset + length exceeds file size + */ + WP_IMAGE_DESCRIPTION_CREATOR_ICC_V1_ERROR_OUT_OF_FILE = 4, +}; +#endif /* WP_IMAGE_DESCRIPTION_CREATOR_ICC_V1_ERROR_ENUM */ + +#define WP_IMAGE_DESCRIPTION_CREATOR_ICC_V1_CREATE 0 +#define WP_IMAGE_DESCRIPTION_CREATOR_ICC_V1_SET_ICC_FILE 1 + + +/** + * @ingroup iface_wp_image_description_creator_icc_v1 + */ +#define WP_IMAGE_DESCRIPTION_CREATOR_ICC_V1_CREATE_SINCE_VERSION 1 +/** + * @ingroup iface_wp_image_description_creator_icc_v1 + */ +#define WP_IMAGE_DESCRIPTION_CREATOR_ICC_V1_SET_ICC_FILE_SINCE_VERSION 1 + +/** @ingroup iface_wp_image_description_creator_icc_v1 */ +static inline void +wp_image_description_creator_icc_v1_set_user_data(struct wp_image_description_creator_icc_v1 *wp_image_description_creator_icc_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_image_description_creator_icc_v1, user_data); +} + +/** @ingroup iface_wp_image_description_creator_icc_v1 */ +static inline void * +wp_image_description_creator_icc_v1_get_user_data(struct wp_image_description_creator_icc_v1 *wp_image_description_creator_icc_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_image_description_creator_icc_v1); +} + +static inline uint32_t +wp_image_description_creator_icc_v1_get_version(struct wp_image_description_creator_icc_v1 *wp_image_description_creator_icc_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_image_description_creator_icc_v1); +} + +/** @ingroup iface_wp_image_description_creator_icc_v1 */ +static inline void +wp_image_description_creator_icc_v1_destroy(struct wp_image_description_creator_icc_v1 *wp_image_description_creator_icc_v1) +{ + wl_proxy_destroy((struct wl_proxy *) wp_image_description_creator_icc_v1); +} + +/** + * @ingroup iface_wp_image_description_creator_icc_v1 + * + * Create an image description object based on the ICC information + * previously set on this object. A compositor must parse the ICC data in + * some undefined but finite amount of time. + * + * The completeness of the parameter set is verified. If the set is not + * complete, the protocol error incomplete_set is raised. For the + * definition of a complete set, see the description of this interface. + * + * If the particular combination of the information is not supported + * by the compositor, the resulting image description object shall + * immediately deliver the wp_image_description_v1.failed event with the + * 'unsupported' cause. If a valid image description was created from the + * information, the wp_image_description_v1.ready event will eventually + * be sent instead. + * + * This request destroys the wp_image_description_creator_icc_v1 object. + * + * The resulting image description object does not allow get_information + * request. + */ +static inline struct wp_image_description_v1 * +wp_image_description_creator_icc_v1_create(struct wp_image_description_creator_icc_v1 *wp_image_description_creator_icc_v1) +{ + struct wl_proxy *image_description; + + image_description = wl_proxy_marshal_flags((struct wl_proxy *) wp_image_description_creator_icc_v1, + WP_IMAGE_DESCRIPTION_CREATOR_ICC_V1_CREATE, &wp_image_description_v1_interface, wl_proxy_get_version((struct wl_proxy *) wp_image_description_creator_icc_v1), WL_MARSHAL_FLAG_DESTROY, NULL); + + return (struct wp_image_description_v1 *) image_description; +} + +/** + * @ingroup iface_wp_image_description_creator_icc_v1 + * + * Sets the ICC profile file to be used as the basis of the image + * description. + * + * The data shall be found through the given fd at the given offset, having + * the given length. The fd must be seekable and readable. Violating these + * requirements raises the bad_fd protocol error. + * + * If reading the data fails due to an error independent of the client, the + * compositor shall send the wp_image_description_v1.failed event on the + * created wp_image_description_v1 with the 'operating_system' cause. + * + * The maximum size of the ICC profile is 32 MB. If length is greater than + * that or zero, the protocol error bad_size is raised. If offset + length + * exceeds the file size, the protocol error out_of_file is raised. + * + * A compositor may read the file at any time starting from this request + * and only until whichever happens first: + * - If create request was issued, the wp_image_description_v1 object + * delivers either failed or ready event; or + * - if create request was not issued, this + * wp_image_description_creator_icc_v1 object is destroyed. + * + * A compositor shall not modify the contents of the file, and the fd may + * be sealed for writes and size changes. The client must ensure to its + * best ability that the data does not change while the compositor is + * reading it. + * + * The data must represent a valid ICC profile. The ICC profile version + * must be 2 or 4, it must be a 3 channel profile and the class must be + * Display or ColorSpace. Violating these requirements will not result in a + * protocol error, but will eventually send the + * wp_image_description_v1.failed event on the created + * wp_image_description_v1 with the 'unsupported' cause. + * + * See the International Color Consortium specification ICC.1:2022 for more + * details about ICC profiles. + * + * If ICC file has already been set on this object, the protocol error + * already_set is raised. + */ +static inline void +wp_image_description_creator_icc_v1_set_icc_file(struct wp_image_description_creator_icc_v1 *wp_image_description_creator_icc_v1, int32_t icc_profile, uint32_t offset, uint32_t length) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_image_description_creator_icc_v1, + WP_IMAGE_DESCRIPTION_CREATOR_ICC_V1_SET_ICC_FILE, NULL, wl_proxy_get_version((struct wl_proxy *) wp_image_description_creator_icc_v1), 0, icc_profile, offset, length); +} + +#ifndef WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_ENUM +#define WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_ENUM +/** + * @ingroup iface_wp_image_description_creator_params_v1 + * protocol errors + */ +enum wp_image_description_creator_params_v1_error { + /** + * incomplete parameter set + */ + WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_INCOMPLETE_SET = 0, + /** + * property already set + */ + WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_ALREADY_SET = 1, + /** + * request not supported + */ + WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_UNSUPPORTED_FEATURE = 2, + /** + * invalid transfer characteristic + */ + WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_INVALID_TF = 3, + /** + * invalid primaries named + */ + WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_INVALID_PRIMARIES_NAMED = 4, + /** + * invalid luminance value or range + */ + WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_INVALID_LUMINANCE = 5, +}; +#endif /* WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_ERROR_ENUM */ + +#define WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_CREATE 0 +#define WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_SET_TF_NAMED 1 +#define WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_SET_TF_POWER 2 +#define WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_SET_PRIMARIES_NAMED 3 +#define WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_SET_PRIMARIES 4 +#define WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_SET_LUMINANCES 5 +#define WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_SET_MASTERING_DISPLAY_PRIMARIES 6 +#define WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_SET_MASTERING_LUMINANCE 7 +#define WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_SET_MAX_CLL 8 +#define WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_SET_MAX_FALL 9 + + +/** + * @ingroup iface_wp_image_description_creator_params_v1 + */ +#define WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_CREATE_SINCE_VERSION 1 +/** + * @ingroup iface_wp_image_description_creator_params_v1 + */ +#define WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_SET_TF_NAMED_SINCE_VERSION 1 +/** + * @ingroup iface_wp_image_description_creator_params_v1 + */ +#define WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_SET_TF_POWER_SINCE_VERSION 1 +/** + * @ingroup iface_wp_image_description_creator_params_v1 + */ +#define WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_SET_PRIMARIES_NAMED_SINCE_VERSION 1 +/** + * @ingroup iface_wp_image_description_creator_params_v1 + */ +#define WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_SET_PRIMARIES_SINCE_VERSION 1 +/** + * @ingroup iface_wp_image_description_creator_params_v1 + */ +#define WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_SET_LUMINANCES_SINCE_VERSION 1 +/** + * @ingroup iface_wp_image_description_creator_params_v1 + */ +#define WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_SET_MASTERING_DISPLAY_PRIMARIES_SINCE_VERSION 1 +/** + * @ingroup iface_wp_image_description_creator_params_v1 + */ +#define WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_SET_MASTERING_LUMINANCE_SINCE_VERSION 1 +/** + * @ingroup iface_wp_image_description_creator_params_v1 + */ +#define WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_SET_MAX_CLL_SINCE_VERSION 1 +/** + * @ingroup iface_wp_image_description_creator_params_v1 + */ +#define WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_SET_MAX_FALL_SINCE_VERSION 1 + +/** @ingroup iface_wp_image_description_creator_params_v1 */ +static inline void +wp_image_description_creator_params_v1_set_user_data(struct wp_image_description_creator_params_v1 *wp_image_description_creator_params_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_image_description_creator_params_v1, user_data); +} + +/** @ingroup iface_wp_image_description_creator_params_v1 */ +static inline void * +wp_image_description_creator_params_v1_get_user_data(struct wp_image_description_creator_params_v1 *wp_image_description_creator_params_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_image_description_creator_params_v1); +} + +static inline uint32_t +wp_image_description_creator_params_v1_get_version(struct wp_image_description_creator_params_v1 *wp_image_description_creator_params_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_image_description_creator_params_v1); +} + +/** @ingroup iface_wp_image_description_creator_params_v1 */ +static inline void +wp_image_description_creator_params_v1_destroy(struct wp_image_description_creator_params_v1 *wp_image_description_creator_params_v1) +{ + wl_proxy_destroy((struct wl_proxy *) wp_image_description_creator_params_v1); +} + +/** + * @ingroup iface_wp_image_description_creator_params_v1 + * + * Create an image description object based on the parameters previously + * set on this object. + * + * The completeness of the parameter set is verified. If the set is not + * complete, the protocol error incomplete_set is raised. For the + * definition of a complete set, see the description of this interface. + * + * When both max_cll and max_fall are set, max_fall must be less or equal + * to max_cll otherwise the invalid_luminance protocol error is raised. + * + * In version 1, these following conditions also result in the + * invalid_luminance protocol error. Version 2 and later do not have this + * requirement. + * - When max_cll is set, it must be greater than min L and less or equal + * to max L of the mastering luminance range. + * - When max_fall is set, it must be greater than min L and less or equal + * to max L of the mastering luminance range. + * + * If the particular combination of the parameter set is not supported + * by the compositor, the resulting image description object shall + * immediately deliver the wp_image_description_v1.failed event with the + * 'unsupported' cause. If a valid image description was created from the + * parameter set, the wp_image_description_v1.ready event will eventually + * be sent instead. + * + * This request destroys the wp_image_description_creator_params_v1 + * object. + * + * The resulting image description object does not allow get_information + * request. + */ +static inline struct wp_image_description_v1 * +wp_image_description_creator_params_v1_create(struct wp_image_description_creator_params_v1 *wp_image_description_creator_params_v1) +{ + struct wl_proxy *image_description; + + image_description = wl_proxy_marshal_flags((struct wl_proxy *) wp_image_description_creator_params_v1, + WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_CREATE, &wp_image_description_v1_interface, wl_proxy_get_version((struct wl_proxy *) wp_image_description_creator_params_v1), WL_MARSHAL_FLAG_DESTROY, NULL); + + return (struct wp_image_description_v1 *) image_description; +} + +/** + * @ingroup iface_wp_image_description_creator_params_v1 + * + * Sets the transfer characteristic using explicitly enumerated named + * functions. + * + * When the resulting image description is attached to an image, the + * content should be decoded according to the industry standard + * practices for the transfer characteristic. + * + * Only names advertised with wp_color_manager_v1 event supported_tf_named + * are allowed. Other values shall raise the protocol error invalid_tf. + * + * If transfer characteristic has already been set on this object, the + * protocol error already_set is raised. + */ +static inline void +wp_image_description_creator_params_v1_set_tf_named(struct wp_image_description_creator_params_v1 *wp_image_description_creator_params_v1, uint32_t tf) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_image_description_creator_params_v1, + WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_SET_TF_NAMED, NULL, wl_proxy_get_version((struct wl_proxy *) wp_image_description_creator_params_v1), 0, tf); +} + +/** + * @ingroup iface_wp_image_description_creator_params_v1 + * + * Sets the color component transfer characteristic to a power curve with + * the given exponent. Negative values are handled by mirroring the + * positive half of the curve through the origin. The valid domain and + * range of the curve are all finite real numbers. This curve represents + * the conversion from electrical to optical color channel values. + * + * The curve exponent shall be multiplied by 10000 to get the argument eexp + * value to carry the precision of 4 decimals. + * + * The curve exponent must be at least 1.0 and at most 10.0. Otherwise the + * protocol error invalid_tf is raised. + * + * If transfer characteristic has already been set on this object, the + * protocol error already_set is raised. + * + * This request can be used when the compositor advertises + * wp_color_manager_v1.feature.set_tf_power. Otherwise this request raises + * the protocol error unsupported_feature. + */ +static inline void +wp_image_description_creator_params_v1_set_tf_power(struct wp_image_description_creator_params_v1 *wp_image_description_creator_params_v1, uint32_t eexp) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_image_description_creator_params_v1, + WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_SET_TF_POWER, NULL, wl_proxy_get_version((struct wl_proxy *) wp_image_description_creator_params_v1), 0, eexp); +} + +/** + * @ingroup iface_wp_image_description_creator_params_v1 + * + * Sets the color primaries and white point using explicitly named sets. + * This describes the primary color volume which is the basis for color + * value encoding. + * + * Only names advertised with wp_color_manager_v1 event + * supported_primaries_named are allowed. Other values shall raise the + * protocol error invalid_primaries_named. + * + * If primaries have already been set on this object, the protocol error + * already_set is raised. + */ +static inline void +wp_image_description_creator_params_v1_set_primaries_named(struct wp_image_description_creator_params_v1 *wp_image_description_creator_params_v1, uint32_t primaries) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_image_description_creator_params_v1, + WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_SET_PRIMARIES_NAMED, NULL, wl_proxy_get_version((struct wl_proxy *) wp_image_description_creator_params_v1), 0, primaries); +} + +/** + * @ingroup iface_wp_image_description_creator_params_v1 + * + * Sets the color primaries and white point using CIE 1931 xy chromaticity + * coordinates. This describes the primary color volume which is the basis + * for color value encoding. + * + * Each coordinate value is multiplied by 1 million to get the argument + * value to carry precision of 6 decimals. + * + * If primaries have already been set on this object, the protocol error + * already_set is raised. + * + * This request can be used if the compositor advertises + * wp_color_manager_v1.feature.set_primaries. Otherwise this request raises + * the protocol error unsupported_feature. + */ +static inline void +wp_image_description_creator_params_v1_set_primaries(struct wp_image_description_creator_params_v1 *wp_image_description_creator_params_v1, int32_t r_x, int32_t r_y, int32_t g_x, int32_t g_y, int32_t b_x, int32_t b_y, int32_t w_x, int32_t w_y) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_image_description_creator_params_v1, + WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_SET_PRIMARIES, NULL, wl_proxy_get_version((struct wl_proxy *) wp_image_description_creator_params_v1), 0, r_x, r_y, g_x, g_y, b_x, b_y, w_x, w_y); +} + +/** + * @ingroup iface_wp_image_description_creator_params_v1 + * + * Sets the primary color volume luminance range and the reference white + * luminance level. These values include the minimum display emission, but + * not external flare. The minimum display emission is assumed to have + * the chromaticity of the primary color volume white point. + * + * The default luminances from + * https://www.color.org/chardata/rgb/srgb.xalter are + * - primary color volume minimum: 0.2 cd/m² + * - primary color volume maximum: 80 cd/m² + * - reference white: 80 cd/m² + * + * Setting a named transfer characteristic can imply other default + * luminances. + * + * The default luminances get overwritten when this request is used. + * With transfer_function.st2084_pq the given 'max_lum' value is ignored, + * and 'max_lum' is taken as 'min_lum' + 10000 cd/m². + * + * 'min_lum' and 'max_lum' specify the minimum and maximum luminances of + * the primary color volume as reproduced by the targeted display. + * + * 'reference_lum' specifies the luminance of the reference white as + * reproduced by the targeted display, and reflects the targeted viewing + * environment. + * + * Compositors should make sure that all content is anchored, meaning that + * an input signal level of 'reference_lum' on one image description and + * another input signal level of 'reference_lum' on another image + * description should produce the same output level, even though the + * 'reference_lum' on both image representations can be different. + * + * 'reference_lum' may be higher than 'max_lum'. In that case reaching + * the reference white output level in image content requires the + * 'extended_target_volume' feature support. + * + * If 'max_lum' or 'reference_lum' are less than or equal to 'min_lum', + * the protocol error invalid_luminance is raised. + * + * The minimum luminance is multiplied by 10000 to get the argument + * 'min_lum' value and carries precision of 4 decimals. The maximum + * luminance and reference white luminance values are unscaled. + * + * If the primary color volume luminance range and the reference white + * luminance level have already been set on this object, the protocol error + * already_set is raised. + * + * This request can be used if the compositor advertises + * wp_color_manager_v1.feature.set_luminances. Otherwise this request + * raises the protocol error unsupported_feature. + */ +static inline void +wp_image_description_creator_params_v1_set_luminances(struct wp_image_description_creator_params_v1 *wp_image_description_creator_params_v1, uint32_t min_lum, uint32_t max_lum, uint32_t reference_lum) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_image_description_creator_params_v1, + WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_SET_LUMINANCES, NULL, wl_proxy_get_version((struct wl_proxy *) wp_image_description_creator_params_v1), 0, min_lum, max_lum, reference_lum); +} + +/** + * @ingroup iface_wp_image_description_creator_params_v1 + * + * Provides the color primaries and white point of the mastering display + * using CIE 1931 xy chromaticity coordinates. This is compatible with the + * SMPTE ST 2086 definition of HDR static metadata. + * + * The mastering display primaries and mastering display luminances define + * the target color volume. + * + * If mastering display primaries are not explicitly set, the target color + * volume is assumed to have the same primaries as the primary color volume. + * + * The target color volume is defined by all tristimulus values between 0.0 + * and 1.0 (inclusive) of the color space defined by the given mastering + * display primaries and white point. The colorimetry is identical between + * the container color space and the mastering display color space, + * including that no chromatic adaptation is applied even if the white + * points differ. + * + * The target color volume can exceed the primary color volume to allow for + * a greater color volume with an existing color space definition (for + * example scRGB). It can be smaller than the primary color volume to + * minimize gamut and tone mapping distances for big color spaces (HDR + * metadata). + * + * To make use of the entire target color volume a suitable pixel format + * has to be chosen (e.g. floating point to exceed the primary color + * volume, or abusing limited quantization range as with xvYCC). + * + * Each coordinate value is multiplied by 1 million to get the argument + * value to carry precision of 6 decimals. + * + * If mastering display primaries have already been set on this object, the + * protocol error already_set is raised. + * + * This request can be used if the compositor advertises + * wp_color_manager_v1.feature.set_mastering_display_primaries. Otherwise + * this request raises the protocol error unsupported_feature. The + * advertisement implies support only for target color volumes fully + * contained within the primary color volume. + * + * If a compositor additionally supports target color volume exceeding the + * primary color volume, it must advertise + * wp_color_manager_v1.feature.extended_target_volume. If a client uses + * target color volume exceeding the primary color volume and the + * compositor does not support it, the result is implementation defined. + * Compositors are recommended to detect this case and fail the image + * description gracefully, but it may as well result in color artifacts. + */ +static inline void +wp_image_description_creator_params_v1_set_mastering_display_primaries(struct wp_image_description_creator_params_v1 *wp_image_description_creator_params_v1, int32_t r_x, int32_t r_y, int32_t g_x, int32_t g_y, int32_t b_x, int32_t b_y, int32_t w_x, int32_t w_y) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_image_description_creator_params_v1, + WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_SET_MASTERING_DISPLAY_PRIMARIES, NULL, wl_proxy_get_version((struct wl_proxy *) wp_image_description_creator_params_v1), 0, r_x, r_y, g_x, g_y, b_x, b_y, w_x, w_y); +} + +/** + * @ingroup iface_wp_image_description_creator_params_v1 + * + * Sets the luminance range that was used during the content mastering + * process as the minimum and maximum absolute luminance L. These values + * include the minimum display emission and ambient flare luminances, + * assumed to be optically additive and have the chromaticity of the + * primary color volume white point. This should be + * compatible with the SMPTE ST 2086 definition of HDR static metadata. + * + * The mastering display primaries and mastering display luminances define + * the target color volume. + * + * If mastering luminances are not explicitly set, the target color volume + * is assumed to have the same min and max luminances as the primary color + * volume. + * + * If max L is less than or equal to min L, the protocol error + * invalid_luminance is raised. + * + * Min L value is multiplied by 10000 to get the argument min_lum value + * and carry precision of 4 decimals. Max L value is unscaled for max_lum. + * + * This request can be used if the compositor advertises + * wp_color_manager_v1.feature.set_mastering_display_primaries. Otherwise + * this request raises the protocol error unsupported_feature. The + * advertisement implies support only for target color volumes fully + * contained within the primary color volume. + * + * If a compositor additionally supports target color volume exceeding the + * primary color volume, it must advertise + * wp_color_manager_v1.feature.extended_target_volume. If a client uses + * target color volume exceeding the primary color volume and the + * compositor does not support it, the result is implementation defined. + * Compositors are recommended to detect this case and fail the image + * description gracefully, but it may as well result in color artifacts. + */ +static inline void +wp_image_description_creator_params_v1_set_mastering_luminance(struct wp_image_description_creator_params_v1 *wp_image_description_creator_params_v1, uint32_t min_lum, uint32_t max_lum) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_image_description_creator_params_v1, + WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_SET_MASTERING_LUMINANCE, NULL, wl_proxy_get_version((struct wl_proxy *) wp_image_description_creator_params_v1), 0, min_lum, max_lum); +} + +/** + * @ingroup iface_wp_image_description_creator_params_v1 + * + * Sets the maximum content light level (max_cll) as defined by CTA-861-H. + * + * max_cll is undefined by default. + */ +static inline void +wp_image_description_creator_params_v1_set_max_cll(struct wp_image_description_creator_params_v1 *wp_image_description_creator_params_v1, uint32_t max_cll) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_image_description_creator_params_v1, + WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_SET_MAX_CLL, NULL, wl_proxy_get_version((struct wl_proxy *) wp_image_description_creator_params_v1), 0, max_cll); +} + +/** + * @ingroup iface_wp_image_description_creator_params_v1 + * + * Sets the maximum frame-average light level (max_fall) as defined by + * CTA-861-H. + * + * max_fall is undefined by default. + */ +static inline void +wp_image_description_creator_params_v1_set_max_fall(struct wp_image_description_creator_params_v1 *wp_image_description_creator_params_v1, uint32_t max_fall) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_image_description_creator_params_v1, + WP_IMAGE_DESCRIPTION_CREATOR_PARAMS_V1_SET_MAX_FALL, NULL, wl_proxy_get_version((struct wl_proxy *) wp_image_description_creator_params_v1), 0, max_fall); +} + +#ifndef WP_IMAGE_DESCRIPTION_V1_ERROR_ENUM +#define WP_IMAGE_DESCRIPTION_V1_ERROR_ENUM +/** + * @ingroup iface_wp_image_description_v1 + * protocol errors + */ +enum wp_image_description_v1_error { + /** + * attempted to use an object which is not ready + */ + WP_IMAGE_DESCRIPTION_V1_ERROR_NOT_READY = 0, + /** + * get_information not allowed + */ + WP_IMAGE_DESCRIPTION_V1_ERROR_NO_INFORMATION = 1, +}; +#endif /* WP_IMAGE_DESCRIPTION_V1_ERROR_ENUM */ + +#ifndef WP_IMAGE_DESCRIPTION_V1_CAUSE_ENUM +#define WP_IMAGE_DESCRIPTION_V1_CAUSE_ENUM +/** + * @ingroup iface_wp_image_description_v1 + * generic reason for failure + */ +enum wp_image_description_v1_cause { + /** + * interface version too low + */ + WP_IMAGE_DESCRIPTION_V1_CAUSE_LOW_VERSION = 0, + /** + * unsupported image description data + */ + WP_IMAGE_DESCRIPTION_V1_CAUSE_UNSUPPORTED = 1, + /** + * error independent of the client + */ + WP_IMAGE_DESCRIPTION_V1_CAUSE_OPERATING_SYSTEM = 2, + /** + * the relevant output no longer exists + */ + WP_IMAGE_DESCRIPTION_V1_CAUSE_NO_OUTPUT = 3, +}; +#endif /* WP_IMAGE_DESCRIPTION_V1_CAUSE_ENUM */ + +/** + * @ingroup iface_wp_image_description_v1 + * @struct wp_image_description_v1_listener + */ +struct wp_image_description_v1_listener { + /** + * graceful error on creating the image description + * + * If creating a wp_image_description_v1 object fails for a + * reason that is not defined as a protocol error, this event is + * sent. + * + * The requests that create image description objects define + * whether and when this can occur. Only such creation requests can + * trigger this event. This event cannot be triggered after the + * image description was successfully formed. + * + * Once this event has been sent, the wp_image_description_v1 + * object will never become ready and it can only be destroyed. + * @param cause generic reason + * @param msg ad hoc human-readable explanation + */ + void (*failed)(void *data, + struct wp_image_description_v1 *wp_image_description_v1, + uint32_t cause, + const char *msg); + /** + * the object is ready to be used (32-bit) + * + * Starting from interface version 2, the 'ready2' event is sent + * instead of this event. + * + * For the definition of this event, see the 'ready2' event. The + * difference to this event is as follows. + * + * The id number is valid only as long as the protocol object is + * alive. If all protocol objects referring to the same image + * description record are destroyed, the id number may be recycled + * for a different image description record. + * @param identity the 32-bit image description id number + * @deprecated Deprecated since version 2 + */ + void (*ready)(void *data, + struct wp_image_description_v1 *wp_image_description_v1, + uint32_t identity); + /** + * the object is ready to be used + * + * Once this event has been sent, the wp_image_description_v1 + * object is deemed "ready". Ready objects can be used to send + * requests and can be used through other interfaces. + * + * Every ready wp_image_description_v1 protocol object refers to an + * underlying image description record in the compositor. Multiple + * protocol objects may end up referring to the same record. + * Clients may identify these "copies" by comparing their id + * numbers: if the numbers from two protocol objects are identical, + * the protocol objects refer to the same image description record. + * Two different image description records cannot have the same id + * number simultaneously. The id number does not change during the + * lifetime of the image description record. + * + * Image description id number is not a protocol object id. Zero is + * reserved as an invalid id number. It shall not be possible for a + * client to refer to an image description by its id number in + * protocol. The id numbers might not be portable between Wayland + * connections. A compositor shall not send an invalid id number. + * + * Compositors must not recycle image description id numbers. + * + * This identity allows clients to de-duplicate image description + * records and avoid get_information request if they already have + * the image description information. + * @param identity_hi high 32 bits of the 64-bit image description id number + * @param identity_lo low 32 bits of the 64-bit image description id number + * @since 2 + */ + void (*ready2)(void *data, + struct wp_image_description_v1 *wp_image_description_v1, + uint32_t identity_hi, + uint32_t identity_lo); +}; + +/** + * @ingroup iface_wp_image_description_v1 + */ +static inline int +wp_image_description_v1_add_listener(struct wp_image_description_v1 *wp_image_description_v1, + const struct wp_image_description_v1_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wp_image_description_v1, + (void (**)(void)) listener, data); +} + +#define WP_IMAGE_DESCRIPTION_V1_DESTROY 0 +#define WP_IMAGE_DESCRIPTION_V1_GET_INFORMATION 1 + +/** + * @ingroup iface_wp_image_description_v1 + */ +#define WP_IMAGE_DESCRIPTION_V1_FAILED_SINCE_VERSION 1 +/** + * @ingroup iface_wp_image_description_v1 + */ +#define WP_IMAGE_DESCRIPTION_V1_READY_SINCE_VERSION 1 +/** + * @ingroup iface_wp_image_description_v1 + */ +#define WP_IMAGE_DESCRIPTION_V1_READY2_SINCE_VERSION 2 + +/** + * @ingroup iface_wp_image_description_v1 + */ +#define WP_IMAGE_DESCRIPTION_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_wp_image_description_v1 + */ +#define WP_IMAGE_DESCRIPTION_V1_GET_INFORMATION_SINCE_VERSION 1 + +/** @ingroup iface_wp_image_description_v1 */ +static inline void +wp_image_description_v1_set_user_data(struct wp_image_description_v1 *wp_image_description_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_image_description_v1, user_data); +} + +/** @ingroup iface_wp_image_description_v1 */ +static inline void * +wp_image_description_v1_get_user_data(struct wp_image_description_v1 *wp_image_description_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_image_description_v1); +} + +static inline uint32_t +wp_image_description_v1_get_version(struct wp_image_description_v1 *wp_image_description_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_image_description_v1); +} + +/** + * @ingroup iface_wp_image_description_v1 + * + * Destroy this object. It is safe to destroy an object which is not ready. + * + * Destroying a wp_image_description_v1 object has no side-effects, not + * even if a wp_color_management_surface_v1.set_image_description has not + * yet been followed by a wl_surface.commit. + */ +static inline void +wp_image_description_v1_destroy(struct wp_image_description_v1 *wp_image_description_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_image_description_v1, + WP_IMAGE_DESCRIPTION_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_image_description_v1), WL_MARSHAL_FLAG_DESTROY); +} + +/** + * @ingroup iface_wp_image_description_v1 + * + * Creates a wp_image_description_info_v1 object which delivers the + * information that makes up the image description. + * + * Not all image description protocol objects allow get_information + * request. Whether it is allowed or not is defined by the request that + * created the object. If get_information is not allowed, the protocol + * error no_information is raised. + */ +static inline struct wp_image_description_info_v1 * +wp_image_description_v1_get_information(struct wp_image_description_v1 *wp_image_description_v1) +{ + struct wl_proxy *information; + + information = wl_proxy_marshal_flags((struct wl_proxy *) wp_image_description_v1, + WP_IMAGE_DESCRIPTION_V1_GET_INFORMATION, &wp_image_description_info_v1_interface, wl_proxy_get_version((struct wl_proxy *) wp_image_description_v1), 0, NULL); + + return (struct wp_image_description_info_v1 *) information; +} + +/** + * @ingroup iface_wp_image_description_info_v1 + * @struct wp_image_description_info_v1_listener + */ +struct wp_image_description_info_v1_listener { + /** + * end of information + * + * Signals the end of information events and destroys the object. + */ + void (*done)(void *data, + struct wp_image_description_info_v1 *wp_image_description_info_v1); + /** + * ICC profile matching the image description + * + * The icc argument provides a file descriptor to the client + * which may be memory-mapped to provide the ICC profile matching + * the image description. The fd is read-only, and if mapped then + * it must be mapped with MAP_PRIVATE by the client. + * + * The ICC profile version and other details are determined by the + * compositor. There is no provision for a client to ask for a + * specific kind of a profile. + * @param icc ICC profile file descriptor + * @param icc_size ICC profile size, in bytes + */ + void (*icc_file)(void *data, + struct wp_image_description_info_v1 *wp_image_description_info_v1, + int32_t icc, + uint32_t icc_size); + /** + * primaries as chromaticity coordinates + * + * Delivers the primary color volume primaries and white point + * using CIE 1931 xy chromaticity coordinates. + * + * Each coordinate value is multiplied by 1 million to get the + * argument value to carry precision of 6 decimals. + * @param r_x Red x * 1M + * @param r_y Red y * 1M + * @param g_x Green x * 1M + * @param g_y Green y * 1M + * @param b_x Blue x * 1M + * @param b_y Blue y * 1M + * @param w_x White x * 1M + * @param w_y White y * 1M + */ + void (*primaries)(void *data, + struct wp_image_description_info_v1 *wp_image_description_info_v1, + int32_t r_x, + int32_t r_y, + int32_t g_x, + int32_t g_y, + int32_t b_x, + int32_t b_y, + int32_t w_x, + int32_t w_y); + /** + * named primaries + * + * Delivers the primary color volume primaries and white point + * using an explicitly enumerated named set. + * @param primaries named primaries + */ + void (*primaries_named)(void *data, + struct wp_image_description_info_v1 *wp_image_description_info_v1, + uint32_t primaries); + /** + * transfer characteristic as a power curve + * + * The color component transfer characteristic of this image + * description is a pure power curve. This event provides the + * exponent of the power function. This curve represents the + * conversion from electrical to optical pixel or color values. + * + * The curve exponent has been multiplied by 10000 to get the + * argument eexp value to carry the precision of 4 decimals. + * @param eexp the exponent * 10000 + */ + void (*tf_power)(void *data, + struct wp_image_description_info_v1 *wp_image_description_info_v1, + uint32_t eexp); + /** + * named transfer characteristic + * + * Delivers the transfer characteristic using an explicitly + * enumerated named function. + * @param tf named transfer function + */ + void (*tf_named)(void *data, + struct wp_image_description_info_v1 *wp_image_description_info_v1, + uint32_t tf); + /** + * primary color volume luminance range and reference white + * + * Delivers the primary color volume luminance range and the + * reference white luminance level. These values include the + * minimum display emission and ambient flare luminances, assumed + * to be optically additive and have the chromaticity of the + * primary color volume white point. + * + * The minimum luminance is multiplied by 10000 to get the argument + * 'min_lum' value and carries precision of 4 decimals. The maximum + * luminance and reference white luminance values are unscaled. + * @param min_lum minimum luminance (cd/m²) * 10000 + * @param max_lum maximum luminance (cd/m²) + * @param reference_lum reference white luminance (cd/m²) + */ + void (*luminances)(void *data, + struct wp_image_description_info_v1 *wp_image_description_info_v1, + uint32_t min_lum, + uint32_t max_lum, + uint32_t reference_lum); + /** + * target primaries as chromaticity coordinates + * + * Provides the color primaries and white point of the target + * color volume using CIE 1931 xy chromaticity coordinates. This is + * compatible with the SMPTE ST 2086 definition of HDR static + * metadata for mastering displays. + * + * While primary color volume is about how color is encoded, the + * target color volume is the actually displayable color volume. If + * target color volume is equal to the primary color volume, then + * this event is not sent. + * + * Each coordinate value is multiplied by 1 million to get the + * argument value to carry precision of 6 decimals. + * @param r_x Red x * 1M + * @param r_y Red y * 1M + * @param g_x Green x * 1M + * @param g_y Green y * 1M + * @param b_x Blue x * 1M + * @param b_y Blue y * 1M + * @param w_x White x * 1M + * @param w_y White y * 1M + */ + void (*target_primaries)(void *data, + struct wp_image_description_info_v1 *wp_image_description_info_v1, + int32_t r_x, + int32_t r_y, + int32_t g_x, + int32_t g_y, + int32_t b_x, + int32_t b_y, + int32_t w_x, + int32_t w_y); + /** + * target luminance range + * + * Provides the luminance range that the image description is + * targeting as the minimum and maximum absolute luminance L. These + * values include the minimum display emission and ambient flare + * luminances, assumed to be optically additive and have the + * chromaticity of the primary color volume white point. This + * should be compatible with the SMPTE ST 2086 definition of HDR + * static metadata. + * + * This luminance range is only theoretical and may not correspond + * to the luminance of light emitted on an actual display. + * + * Min L value is multiplied by 10000 to get the argument min_lum + * value and carry precision of 4 decimals. Max L value is unscaled + * for max_lum. + * @param min_lum min L (cd/m²) * 10000 + * @param max_lum max L (cd/m²) + */ + void (*target_luminance)(void *data, + struct wp_image_description_info_v1 *wp_image_description_info_v1, + uint32_t min_lum, + uint32_t max_lum); + /** + * target maximum content light level + * + * Provides the targeted max_cll of the image description. + * max_cll is defined by CTA-861-H. + * + * This luminance is only theoretical and may not correspond to the + * luminance of light emitted on an actual display. + * @param max_cll Maximum content light-level (cd/m²) + */ + void (*target_max_cll)(void *data, + struct wp_image_description_info_v1 *wp_image_description_info_v1, + uint32_t max_cll); + /** + * target maximum frame-average light level + * + * Provides the targeted max_fall of the image description. + * max_fall is defined by CTA-861-H. + * + * This luminance is only theoretical and may not correspond to the + * luminance of light emitted on an actual display. + * @param max_fall Maximum frame-average light level (cd/m²) + */ + void (*target_max_fall)(void *data, + struct wp_image_description_info_v1 *wp_image_description_info_v1, + uint32_t max_fall); +}; + +/** + * @ingroup iface_wp_image_description_info_v1 + */ +static inline int +wp_image_description_info_v1_add_listener(struct wp_image_description_info_v1 *wp_image_description_info_v1, + const struct wp_image_description_info_v1_listener *listener, void *data) +{ + return wl_proxy_add_listener((struct wl_proxy *) wp_image_description_info_v1, + (void (**)(void)) listener, data); +} + +/** + * @ingroup iface_wp_image_description_info_v1 + */ +#define WP_IMAGE_DESCRIPTION_INFO_V1_DONE_SINCE_VERSION 1 +/** + * @ingroup iface_wp_image_description_info_v1 + */ +#define WP_IMAGE_DESCRIPTION_INFO_V1_ICC_FILE_SINCE_VERSION 1 +/** + * @ingroup iface_wp_image_description_info_v1 + */ +#define WP_IMAGE_DESCRIPTION_INFO_V1_PRIMARIES_SINCE_VERSION 1 +/** + * @ingroup iface_wp_image_description_info_v1 + */ +#define WP_IMAGE_DESCRIPTION_INFO_V1_PRIMARIES_NAMED_SINCE_VERSION 1 +/** + * @ingroup iface_wp_image_description_info_v1 + */ +#define WP_IMAGE_DESCRIPTION_INFO_V1_TF_POWER_SINCE_VERSION 1 +/** + * @ingroup iface_wp_image_description_info_v1 + */ +#define WP_IMAGE_DESCRIPTION_INFO_V1_TF_NAMED_SINCE_VERSION 1 +/** + * @ingroup iface_wp_image_description_info_v1 + */ +#define WP_IMAGE_DESCRIPTION_INFO_V1_LUMINANCES_SINCE_VERSION 1 +/** + * @ingroup iface_wp_image_description_info_v1 + */ +#define WP_IMAGE_DESCRIPTION_INFO_V1_TARGET_PRIMARIES_SINCE_VERSION 1 +/** + * @ingroup iface_wp_image_description_info_v1 + */ +#define WP_IMAGE_DESCRIPTION_INFO_V1_TARGET_LUMINANCE_SINCE_VERSION 1 +/** + * @ingroup iface_wp_image_description_info_v1 + */ +#define WP_IMAGE_DESCRIPTION_INFO_V1_TARGET_MAX_CLL_SINCE_VERSION 1 +/** + * @ingroup iface_wp_image_description_info_v1 + */ +#define WP_IMAGE_DESCRIPTION_INFO_V1_TARGET_MAX_FALL_SINCE_VERSION 1 + + +/** @ingroup iface_wp_image_description_info_v1 */ +static inline void +wp_image_description_info_v1_set_user_data(struct wp_image_description_info_v1 *wp_image_description_info_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_image_description_info_v1, user_data); +} + +/** @ingroup iface_wp_image_description_info_v1 */ +static inline void * +wp_image_description_info_v1_get_user_data(struct wp_image_description_info_v1 *wp_image_description_info_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_image_description_info_v1); +} + +static inline uint32_t +wp_image_description_info_v1_get_version(struct wp_image_description_info_v1 *wp_image_description_info_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_image_description_info_v1); +} + +/** @ingroup iface_wp_image_description_info_v1 */ +static inline void +wp_image_description_info_v1_destroy(struct wp_image_description_info_v1 *wp_image_description_info_v1) +{ + wl_proxy_destroy((struct wl_proxy *) wp_image_description_info_v1); +} + +#define WP_IMAGE_DESCRIPTION_REFERENCE_V1_DESTROY 0 + + +/** + * @ingroup iface_wp_image_description_reference_v1 + */ +#define WP_IMAGE_DESCRIPTION_REFERENCE_V1_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_wp_image_description_reference_v1 */ +static inline void +wp_image_description_reference_v1_set_user_data(struct wp_image_description_reference_v1 *wp_image_description_reference_v1, void *user_data) +{ + wl_proxy_set_user_data((struct wl_proxy *) wp_image_description_reference_v1, user_data); +} + +/** @ingroup iface_wp_image_description_reference_v1 */ +static inline void * +wp_image_description_reference_v1_get_user_data(struct wp_image_description_reference_v1 *wp_image_description_reference_v1) +{ + return wl_proxy_get_user_data((struct wl_proxy *) wp_image_description_reference_v1); +} + +static inline uint32_t +wp_image_description_reference_v1_get_version(struct wp_image_description_reference_v1 *wp_image_description_reference_v1) +{ + return wl_proxy_get_version((struct wl_proxy *) wp_image_description_reference_v1); +} + +/** + * @ingroup iface_wp_image_description_reference_v1 + * + * Destroy this object. This has no effect on the referenced image + * description. + */ +static inline void +wp_image_description_reference_v1_destroy(struct wp_image_description_reference_v1 *wp_image_description_reference_v1) +{ + wl_proxy_marshal_flags((struct wl_proxy *) wp_image_description_reference_v1, + WP_IMAGE_DESCRIPTION_REFERENCE_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wp_image_description_reference_v1), WL_MARSHAL_FLAG_DESTROY); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/detection/displayserver/linux/wayland/wp-color-management-v1-protocol.c b/src/detection/displayserver/linux/wayland/wp-color-management-v1-protocol.c new file mode 100644 index 0000000000..fd2ce26bd5 --- /dev/null +++ b/src/detection/displayserver/linux/wayland/wp-color-management-v1-protocol.c @@ -0,0 +1,225 @@ +#ifdef FF_HAVE_WAYLAND + +/* Generated by wayland-scanner 1.24.0 */ + +/* + * Copyright 2019 Sebastian Wick + * Copyright 2019 Erwin Burema + * Copyright 2020 AMD + * Copyright 2020-2024 Collabora, Ltd. + * Copyright 2024 Xaver Hugl + * Copyright 2022-2025 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include + +extern const struct wl_interface wl_output_interface; +extern const struct wl_interface wl_surface_interface; +extern const struct wl_interface wp_color_management_output_v1_interface; +extern const struct wl_interface wp_color_management_surface_feedback_v1_interface; +extern const struct wl_interface wp_color_management_surface_v1_interface; +extern const struct wl_interface wp_image_description_creator_icc_v1_interface; +extern const struct wl_interface wp_image_description_creator_params_v1_interface; +extern const struct wl_interface wp_image_description_info_v1_interface; +extern const struct wl_interface wp_image_description_reference_v1_interface; +extern const struct wl_interface wp_image_description_v1_interface; + +static const struct wl_interface *color_management_v1_types[] = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &wp_color_management_output_v1_interface, + &wl_output_interface, + &wp_color_management_surface_v1_interface, + &wl_surface_interface, + &wp_color_management_surface_feedback_v1_interface, + &wl_surface_interface, + &wp_image_description_creator_icc_v1_interface, + &wp_image_description_creator_params_v1_interface, + &wp_image_description_v1_interface, + &wp_image_description_v1_interface, + &wp_image_description_reference_v1_interface, + &wp_image_description_v1_interface, + &wp_image_description_v1_interface, + NULL, + &wp_image_description_v1_interface, + &wp_image_description_v1_interface, + &wp_image_description_v1_interface, + &wp_image_description_v1_interface, + &wp_image_description_info_v1_interface, +}; + +static const struct wl_message wp_color_manager_v1_requests[] = { + { "destroy", "", color_management_v1_types + 0 }, + { "get_output", "no", color_management_v1_types + 8 }, + { "get_surface", "no", color_management_v1_types + 10 }, + { "get_surface_feedback", "no", color_management_v1_types + 12 }, + { "create_icc_creator", "n", color_management_v1_types + 14 }, + { "create_parametric_creator", "n", color_management_v1_types + 15 }, + { "create_windows_scrgb", "n", color_management_v1_types + 16 }, + { "get_image_description", "2no", color_management_v1_types + 17 }, +}; + +static const struct wl_message wp_color_manager_v1_events[] = { + { "supported_intent", "u", color_management_v1_types + 0 }, + { "supported_feature", "u", color_management_v1_types + 0 }, + { "supported_tf_named", "u", color_management_v1_types + 0 }, + { "supported_primaries_named", "u", color_management_v1_types + 0 }, + { "done", "", color_management_v1_types + 0 }, +}; + +WL_EXPORT const struct wl_interface wp_color_manager_v1_interface = { + "wp_color_manager_v1", 2, + 8, wp_color_manager_v1_requests, + 5, wp_color_manager_v1_events, +}; + +static const struct wl_message wp_color_management_output_v1_requests[] = { + { "destroy", "", color_management_v1_types + 0 }, + { "get_image_description", "n", color_management_v1_types + 19 }, +}; + +static const struct wl_message wp_color_management_output_v1_events[] = { + { "image_description_changed", "", color_management_v1_types + 0 }, +}; + +WL_EXPORT const struct wl_interface wp_color_management_output_v1_interface = { + "wp_color_management_output_v1", 2, + 2, wp_color_management_output_v1_requests, + 1, wp_color_management_output_v1_events, +}; + +static const struct wl_message wp_color_management_surface_v1_requests[] = { + { "destroy", "", color_management_v1_types + 0 }, + { "set_image_description", "ou", color_management_v1_types + 20 }, + { "unset_image_description", "", color_management_v1_types + 0 }, +}; + +WL_EXPORT const struct wl_interface wp_color_management_surface_v1_interface = { + "wp_color_management_surface_v1", 2, + 3, wp_color_management_surface_v1_requests, + 0, NULL, +}; + +static const struct wl_message wp_color_management_surface_feedback_v1_requests[] = { + { "destroy", "", color_management_v1_types + 0 }, + { "get_preferred", "n", color_management_v1_types + 22 }, + { "get_preferred_parametric", "n", color_management_v1_types + 23 }, +}; + +static const struct wl_message wp_color_management_surface_feedback_v1_events[] = { + { "preferred_changed", "u", color_management_v1_types + 0 }, + { "preferred_changed2", "2uu", color_management_v1_types + 0 }, +}; + +WL_EXPORT const struct wl_interface wp_color_management_surface_feedback_v1_interface = { + "wp_color_management_surface_feedback_v1", 2, + 3, wp_color_management_surface_feedback_v1_requests, + 2, wp_color_management_surface_feedback_v1_events, +}; + +static const struct wl_message wp_image_description_creator_icc_v1_requests[] = { + { "create", "n", color_management_v1_types + 24 }, + { "set_icc_file", "huu", color_management_v1_types + 0 }, +}; + +WL_EXPORT const struct wl_interface wp_image_description_creator_icc_v1_interface = { + "wp_image_description_creator_icc_v1", 2, + 2, wp_image_description_creator_icc_v1_requests, + 0, NULL, +}; + +static const struct wl_message wp_image_description_creator_params_v1_requests[] = { + { "create", "n", color_management_v1_types + 25 }, + { "set_tf_named", "u", color_management_v1_types + 0 }, + { "set_tf_power", "u", color_management_v1_types + 0 }, + { "set_primaries_named", "u", color_management_v1_types + 0 }, + { "set_primaries", "iiiiiiii", color_management_v1_types + 0 }, + { "set_luminances", "uuu", color_management_v1_types + 0 }, + { "set_mastering_display_primaries", "iiiiiiii", color_management_v1_types + 0 }, + { "set_mastering_luminance", "uu", color_management_v1_types + 0 }, + { "set_max_cll", "u", color_management_v1_types + 0 }, + { "set_max_fall", "u", color_management_v1_types + 0 }, +}; + +WL_EXPORT const struct wl_interface wp_image_description_creator_params_v1_interface = { + "wp_image_description_creator_params_v1", 2, + 10, wp_image_description_creator_params_v1_requests, + 0, NULL, +}; + +static const struct wl_message wp_image_description_v1_requests[] = { + { "destroy", "", color_management_v1_types + 0 }, + { "get_information", "n", color_management_v1_types + 26 }, +}; + +static const struct wl_message wp_image_description_v1_events[] = { + { "failed", "us", color_management_v1_types + 0 }, + { "ready", "u", color_management_v1_types + 0 }, + { "ready2", "2uu", color_management_v1_types + 0 }, +}; + +WL_EXPORT const struct wl_interface wp_image_description_v1_interface = { + "wp_image_description_v1", 2, + 2, wp_image_description_v1_requests, + 3, wp_image_description_v1_events, +}; + +static const struct wl_message wp_image_description_info_v1_events[] = { + { "done", "", color_management_v1_types + 0 }, + { "icc_file", "hu", color_management_v1_types + 0 }, + { "primaries", "iiiiiiii", color_management_v1_types + 0 }, + { "primaries_named", "u", color_management_v1_types + 0 }, + { "tf_power", "u", color_management_v1_types + 0 }, + { "tf_named", "u", color_management_v1_types + 0 }, + { "luminances", "uuu", color_management_v1_types + 0 }, + { "target_primaries", "iiiiiiii", color_management_v1_types + 0 }, + { "target_luminance", "uu", color_management_v1_types + 0 }, + { "target_max_cll", "u", color_management_v1_types + 0 }, + { "target_max_fall", "u", color_management_v1_types + 0 }, +}; + +WL_EXPORT const struct wl_interface wp_image_description_info_v1_interface = { + "wp_image_description_info_v1", 2, + 0, NULL, + 11, wp_image_description_info_v1_events, +}; + +static const struct wl_message wp_image_description_reference_v1_requests[] = { + { "destroy", "", color_management_v1_types + 0 }, +}; + +WL_EXPORT const struct wl_interface wp_image_description_reference_v1_interface = { + "wp_image_description_reference_v1", 1, + 1, wp_image_description_reference_v1_requests, + 0, NULL, +}; + +#endif diff --git a/src/detection/displayserver/linux/wayland/xdg-output-unstable-v1-protocol.c b/src/detection/displayserver/linux/wayland/xdg-output-unstable-v1-protocol.c index 76f62575d9..fb1273e63f 100644 --- a/src/detection/displayserver/linux/wayland/xdg-output-unstable-v1-protocol.c +++ b/src/detection/displayserver/linux/wayland/xdg-output-unstable-v1-protocol.c @@ -35,7 +35,7 @@ static const struct wl_interface* xdg_output_unstable_v1_types[] = { NULL, NULL, &zxdg_output_v1_interface, - NULL, // &wl_output_interface, + &wl_output_interface, }; static const struct wl_message zxdg_output_manager_v1_requests[] = { diff --git a/src/detection/displayserver/linux/wayland/zwlr-output.c b/src/detection/displayserver/linux/wayland/zwlr-output.c deleted file mode 100644 index 632bd19b40..0000000000 --- a/src/detection/displayserver/linux/wayland/zwlr-output.c +++ /dev/null @@ -1,212 +0,0 @@ -#ifdef FF_HAVE_WAYLAND - - #include "wayland.h" - #include "wlr-output-management-unstable-v1-client-protocol.h" - -static void waylandZwlrTransformListener(void* data, FF_A_UNUSED struct zwlr_output_head_v1* zwlr_output_head_v1, int32_t transform) { - WaylandDisplay* wldata = (WaylandDisplay*) data; - wldata->transform = (enum wl_output_transform) transform; -} - -static void waylandZwlrScaleListener(void* data, FF_A_UNUSED struct zwlr_output_head_v1* zwlr_output_head_v1, wl_fixed_t scale) { - WaylandDisplay* wldata = (WaylandDisplay*) data; - wldata->dpi = (uint32_t) scale * 3 / 8; // wl_fixed_to_double(scale) * 96; -} - -typedef struct WaylandZwlrMode { - int32_t width; - int32_t height; - int32_t refreshRate; - bool preferred; - struct zwlr_output_mode_v1* pMode; -} WaylandZwlrMode; - -static void waylandZwlrModeSizeListener(void* data, FF_A_UNUSED struct zwlr_output_mode_v1* zwlr_output_mode_v1, int32_t width, int32_t height) { - WaylandZwlrMode* mode = (WaylandZwlrMode*) data; - mode->width = width; - mode->height = height; -} - -static void waylandZwlrModeRefreshListener(void* data, FF_A_UNUSED struct zwlr_output_mode_v1* zwlr_output_mode_v1, int32_t rate) { - WaylandZwlrMode* mode = (WaylandZwlrMode*) data; - mode->refreshRate = rate; -} - -static void waylandZwlrModePreferredListener(void* data, FF_A_UNUSED struct zwlr_output_mode_v1* zwlr_output_mode_v1) { - WaylandZwlrMode* mode = (WaylandZwlrMode*) data; - mode->preferred = true; -} - -static const struct zwlr_output_mode_v1_listener modeListener = { - .size = waylandZwlrModeSizeListener, - .refresh = waylandZwlrModeRefreshListener, - .preferred = waylandZwlrModePreferredListener, - .finished = (void*) stubListener, -}; - -static void waylandZwlrModeListener(void* data, FF_A_UNUSED struct zwlr_output_head_v1* zwlr_output_head_v1, struct zwlr_output_mode_v1* mode) { - WaylandDisplay* wldata = (WaylandDisplay*) data; - if (!wldata->internal) { - return; - } - - WaylandZwlrMode* newMode = FF_LIST_ADD(WaylandZwlrMode, *(FFlist*) wldata->internal); - *newMode = (WaylandZwlrMode) { .pMode = mode }; - - // Strangely, the listener is called only in this function, but not in `waylandZwlrCurrentModeListener` - wldata->parent->ffwl_proxy_add_listener((struct wl_proxy*) mode, (void (**)(void)) &modeListener, newMode); -} - -static void waylandZwlrCurrentModeListener(void* data, FF_A_UNUSED struct zwlr_output_head_v1* zwlr_output_head_v1, struct zwlr_output_mode_v1* mode) { - // waylandZwlrModeListener is always run before this - WaylandDisplay* wldata = (WaylandDisplay*) data; - if (!wldata->internal) { - return; - } - - int set = 0; - FF_LIST_FOR_EACH (WaylandZwlrMode, m, *(FFlist*) wldata->internal) { - if (m->pMode == mode) { - wldata->width = m->width; - wldata->height = m->height; - wldata->refreshRate = m->refreshRate; - if (++set == 2) { - break; - } - } - if (m->preferred) { - wldata->preferredWidth = m->width; - wldata->preferredHeight = m->height; - wldata->preferredRefreshRate = m->refreshRate; - if (++set == 2) { - break; - } - } - } -} - -static void waylandZwlrPhysicalSizeListener(void* data, FF_A_UNUSED struct zwlr_output_head_v1* zwlr_output_head_v1, int32_t width, int32_t height) { - WaylandDisplay* wldata = (WaylandDisplay*) data; - wldata->physicalWidth = width; - wldata->physicalHeight = height; -} - -static void waylandZwlrEnabledListener(void* data, FF_A_UNUSED struct zwlr_output_head_v1* zwlr_output_head_v1, bool enabled) { - WaylandDisplay* wldata = (WaylandDisplay*) data; - if (!enabled) { - wldata->internal = NULL; - } -} - -static const struct zwlr_output_head_v1_listener headListener = { - .name = (void*) ffWaylandOutputNameListener, - .description = (void*) ffWaylandOutputDescriptionListener, - .physical_size = waylandZwlrPhysicalSizeListener, - .mode = waylandZwlrModeListener, - .enabled = (void*) waylandZwlrEnabledListener, - .current_mode = waylandZwlrCurrentModeListener, - .position = (void*) stubListener, - .transform = waylandZwlrTransformListener, - .scale = waylandZwlrScaleListener, - .finished = (void*) stubListener, - .make = (void*) stubListener, - .model = (void*) stubListener, - .serial_number = (void*) stubListener, - .adaptive_sync = (void*) stubListener, -}; - -static void waylandHandleZwlrHead(void* data, FF_A_UNUSED struct zwlr_output_manager_v1* zwlr_output_manager_v1, struct zwlr_output_head_v1* head) { - WaylandData* wldata = data; - - FF_LIST_AUTO_DESTROY modes = ffListCreate(); - WaylandDisplay display = { - .parent = wldata, - .transform = WL_OUTPUT_TRANSFORM_NORMAL, - .type = FF_DISPLAY_TYPE_UNKNOWN, - .name = ffStrbufCreate(), - .description = ffStrbufCreate(), - .edidName = ffStrbufCreate(), - .internal = &modes, - }; - - wldata->ffwl_proxy_add_listener((struct wl_proxy*) head, (void (**)(void)) &headListener, &display); - wldata->ffwl_display_roundtrip(wldata->display); - - if (display.width <= 0 || display.height <= 0 || !display.internal) { - return; - } - - uint32_t rotation = ffWaylandHandleRotation(&display); - - FFDisplayResult* item = ffdsAppendDisplay(wldata->result, - (uint32_t) display.width, - (uint32_t) display.height, - display.refreshRate / 1000.0, - (uint32_t) display.dpi, - (uint32_t) display.preferredWidth, - (uint32_t) display.preferredHeight, - display.preferredRefreshRate / 1000.0, - rotation, - display.edidName.length - ? &display.edidName - : display.description.length && !ffStrbufContain(&display.description, &display.name) - ? &display.description - : &display.name, - display.type, - false, - display.id, - (uint32_t) display.physicalWidth, - (uint32_t) display.physicalHeight, - "wayland-zwlr"); - if (item) { - if (display.hdrSupported) { - item->hdrStatus = FF_DISPLAY_HDR_STATUS_SUPPORTED; - } else if (display.hdrInfoAvailable) { - item->hdrStatus = FF_DISPLAY_HDR_STATUS_UNSUPPORTED; - } else { - item->hdrStatus = FF_DISPLAY_HDR_STATUS_UNKNOWN; - } - - item->manufactureYear = display.myear; - item->manufactureWeek = display.mweek; - item->serial = display.serial; - } - - ffStrbufDestroy(&display.description); - ffStrbufDestroy(&display.name); - ffStrbufDestroy(&display.edidName); - - // These must be released manually - FF_LIST_FOR_EACH (WaylandZwlrMode, m, modes) { - wldata->ffwl_proxy_destroy((void*) m->pMode); - } - wldata->ffwl_proxy_destroy((void*) head); -} - -static const struct zwlr_output_manager_v1_listener outputListener = { - .head = waylandHandleZwlrHead, - .done = (void*) stubListener, - .finished = (void*) stubListener, -}; - -const char* ffWaylandHandleZwlrOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version) { - uint32_t bindVersion = min(version, ZWLR_OUTPUT_MANAGER_V1_HEAD_SINCE_VERSION); - struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &zwlr_output_manager_v1_interface, bindVersion, name, zwlr_output_manager_v1_interface.name, bindVersion, NULL); - if (output == NULL) { - return "Failed to bind zwlr_output_manager_v1"; - } - - if (wldata->ffwl_proxy_add_listener(output, (void (**)(void)) &outputListener, wldata) < 0) { - wldata->ffwl_proxy_destroy(output); - return "Failed to add listener to zwlr_output_manager_v1"; - } - if (wldata->ffwl_display_roundtrip(wldata->display) < 0) { - wldata->ffwl_proxy_destroy(output); - return "Failed to roundtrip display"; - } - wldata->ffwl_proxy_destroy(output); - - return NULL; -} - -#endif diff --git a/src/detection/displayserver/linux/xcb.c b/src/detection/displayserver/linux/xcb.c index 8620d71508..8ad663d173 100644 --- a/src/detection/displayserver/linux/xcb.c +++ b/src/detection/displayserver/linux/xcb.c @@ -227,7 +227,8 @@ static bool xcbRandrHandleOutput(XcbRandrData* data, xcb_randr_output_t output, if (item) { if (edidData && edidLength >= 128) { item->hdrStatus = ffEdidGetHdrCompatible(edidData, (uint32_t) edidLength) ? FF_DISPLAY_HDR_STATUS_SUPPORTED : FF_DISPLAY_HDR_STATUS_UNSUPPORTED; - ffEdidGetSerialAndManufactureDate(edidData, &item->serial, &item->manufactureYear, &item->manufactureWeek); + ffEdidGetManufactureDate(edidData, &item->manufactureYear, &item->manufactureWeek); + ffEdidGetSerial(edidData, &item->serial); } item->bitDepth = bitDepth; if ((rotation == 90 || rotation == 180) && !randrEmulation) { diff --git a/src/detection/displayserver/linux/xlib.c b/src/detection/displayserver/linux/xlib.c index 2beffccabf..642a0d2f22 100644 --- a/src/detection/displayserver/linux/xlib.c +++ b/src/detection/displayserver/linux/xlib.c @@ -161,7 +161,8 @@ static bool xrandrHandleCrtc(XrandrData* data, XRROutputInfo* output, FFstrbuf* if (item) { if (edidLength) { item->hdrStatus = ffEdidGetHdrCompatible(edidData, edidLength) ? FF_DISPLAY_HDR_STATUS_SUPPORTED : FF_DISPLAY_HDR_STATUS_UNSUPPORTED; - ffEdidGetSerialAndManufactureDate(edidData, &item->serial, &item->manufactureYear, &item->manufactureWeek); + ffEdidGetManufactureDate(edidData, &item->manufactureYear, &item->manufactureWeek); + ffEdidGetSerial(edidData, &item->serial); } item->bitDepth = bitDepth; if ((rotation == 90 || rotation == 180) && !randrEmulation) { diff --git a/src/detection/gpu/adl.h b/src/detection/gpu/adl.h index 346eece871..18510c9530 100644 --- a/src/detection/gpu/adl.h +++ b/src/detection/gpu/adl.h @@ -26,6 +26,9 @@ extern int ADL2_Adapter_DedicatedVRAMUsage_Get(ADL_CONTEXT_HANDLE context, int i // Function to get the ASICFamilyType from the adapter. extern int ADL2_Adapter_ASICFamilyType_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, int* lpAsicTypes, int* lpValids); +// This function retrieves the chipset information for a specified adapter. +extern int ADL2_Adapter_ChipSetInfo_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, ADLChipSetInfo* lpChipSetInfo); + // Function to retrieve current power management capabilities. extern int ADL2_Overdrive_Caps(ADL_CONTEXT_HANDLE context, int iAdapterIndex, int* iSupported, int* iEnabled, int* iVersion); diff --git a/src/detection/gpu/asahi_drm.h b/src/detection/gpu/asahi_drm.h index 69b537b757..953caefe5a 100644 --- a/src/detection/gpu/asahi_drm.h +++ b/src/detection/gpu/asahi_drm.h @@ -7,7 +7,11 @@ #ifndef _ASAHI_DRM_H_ #define _ASAHI_DRM_H_ -#include +#if __has_include() + #include +#else + #include +#endif #if defined(__cplusplus) extern "C" { diff --git a/src/detection/gpu/d3dkmthk.h b/src/detection/gpu/d3dkmthk.h index da0087bae6..e32241164c 100644 --- a/src/detection/gpu/d3dkmthk.h +++ b/src/detection/gpu/d3dkmthk.h @@ -152,6 +152,18 @@ typedef struct _D3DKMT_QUERY_DEVICE_IDS { D3DKMT_DEVICE_IDS DeviceIds; // out: } D3DKMT_QUERY_DEVICE_IDS; +typedef enum _D3DKMT_PNP_KEY_TYPE { + D3DKMT_PNP_KEY_HARDWARE, + D3DKMT_PNP_KEY_SOFTWARE +} D3DKMT_PNP_KEY_TYPE; + +typedef struct _D3DKMT_QUERY_PHYSICAL_ADAPTER_PNP_KEY { + UINT PhysicalAdapterIndex; + D3DKMT_PNP_KEY_TYPE PnPKeyType; + WCHAR* pDest; + UINT* pCchDest; +} D3DKMT_QUERY_PHYSICAL_ADAPTER_PNP_KEY; + typedef enum _QAI_DRIVERVERSION { KMT_DRIVERVERSION_WDDM_1_0 = 1000, // Windows Vista KMT_DRIVERVERSION_WDDM_1_1_PRERELEASE = 1102, // Windows Vista with prereleased Win7 features @@ -187,6 +199,7 @@ typedef enum _KMTQUERYADAPTERINFOTYPE { KMTQAITYPE_UMD_DRIVER_VERSION = 18, KMTQAITYPE_NODEMETADATA = 25, // WDDM 2.0, Windows 10 KMTQAITYPE_PHYSICALADAPTERDEVICEIDS = 31, + KMTQAITYPE_PHYSICALADAPTERPNPKEY = 41, // WDDM 2.2, Windows 10 (1703) KMTQAITYPE_QUERY_ADAPTER_UNIQUE_GUID = 60, // WDDM 2.4, Windows 10 (1803) KMTQAITYPE_NODEPERFDATA = 61, KMTQAITYPE_ADAPTERPERFDATA = 62, diff --git a/src/detection/gpu/gpu.c b/src/detection/gpu/gpu.c index a287298da7..bf6cde9b68 100644 --- a/src/detection/gpu/gpu.c +++ b/src/detection/gpu/gpu.c @@ -77,6 +77,25 @@ const char* ffGPUGetVendorString(unsigned vendorId) { } } +static bool normalizeVendorName(FFGPUResult* gpu) { + if (ffStrbufContainS(&gpu->name, "Apple")) { + ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_APPLE); + gpu->type = FF_GPU_TYPE_INTEGRATED; + } else if (ffStrbufContainS(&gpu->name, "Intel")) { + ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_INTEL); + } else if (ffStrbufContainS(&gpu->name, "AMD") || ffStrbufContainS(&gpu->name, "ATI")) { + ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_AMD); + } else if (ffStrbufContainS(&gpu->name, "NVIDIA")) { + ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_NVIDIA); + } else if (ffStrbufContainS(&gpu->name, "MTT")) { + ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_MTHREADS); + } else { + return false; + } + + return true; +} + const char* detectByOpenGL(FFlist* gpus) { FF_DEBUG("Starting OpenGL GPU detection fallback"); @@ -107,24 +126,14 @@ const char* detectByOpenGL(FFlist* gpus) { gpu->coreUsage = FF_GPU_CORE_USAGE_UNSET; gpu->dedicated = gpu->shared = (FFGPUMemory) { 0, 0 }; gpu->deviceId = 0; + gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET; FF_DEBUG("OpenGL reported renderer='%s', vendor='%s', version='%s'", gpu->name.chars, gpu->vendor.chars, result.version.chars); - if (ffStrbufContainS(&gpu->name, "Apple")) { - ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_APPLE); - gpu->type = FF_GPU_TYPE_INTEGRATED; - } else if (ffStrbufContainS(&gpu->name, "Intel")) { - ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_INTEL); - } else if (ffStrbufContainS(&gpu->name, "AMD") || ffStrbufContainS(&gpu->name, "ATI")) { - ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_AMD); - } else if (ffStrbufContainS(&gpu->name, "NVIDIA")) { - ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_NVIDIA); - } else if (ffStrbufContainS(&gpu->name, "MTT")) { - ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_MTHREADS); - } + normalizeVendorName(gpu); FF_DEBUG("OpenGL fallback produced GPU: name='%s', vendor='%s', type=%u", gpu->name.chars, @@ -140,6 +149,98 @@ const char* detectByOpenGL(FFlist* gpus) { return error; } +#if defined(FF_HAVE_EGL) || __has_include() + #include + #include + + #if EGL_EXT_device_base && EGL_EXT_device_persistent_id && EGL_EXT_device_query_name + + #define FF_HAVE_EGL_EXT 1 + #include + + #include "common/library.h" + #include "common/strutil.h" + #include "common/io.h" + +const char* detectByEglext(FFlist* result) { + FF_LIBRARY_LOAD_MESSAGE(egl, "libEGL" FF_LIBRARY_EXTENSION, 1); + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(egl, eglGetProcAddress); + + PFNEGLQUERYDEVICESEXTPROC ffeglQueryDevicesEXT = (PFNEGLQUERYDEVICESEXTPROC) ffeglGetProcAddress("eglQueryDevicesEXT"); + if (!ffeglQueryDevicesEXT) { + return "eglQueryDevicesEXT is unavailable"; + } + PFNEGLQUERYDEVICESTRINGEXTPROC ffeglQueryDeviceStringEXT = (PFNEGLQUERYDEVICESTRINGEXTPROC) ffeglGetProcAddress("eglQueryDeviceStringEXT"); + if (!ffeglQueryDeviceStringEXT) { + return "eglQueryDeviceStringEXT is unavailable"; + } + PFNEGLQUERYDEVICEBINARYEXTPROC ffeglQueryDeviceBinaryEXT = (PFNEGLQUERYDEVICEBINARYEXTPROC) ffeglGetProcAddress("eglQueryDeviceBinaryEXT"); + if (!ffeglQueryDeviceBinaryEXT) { + return "eglQueryDeviceBinaryEXT is unavailable"; + } + + FF_DEBUG("Loaded EGL library and required symbols"); + + FF_SUPPRESS_IO(); + + EGLDeviceEXT devices[16]; + EGLint numDevices; + if (ffeglQueryDevicesEXT(ARRAY_SIZE(devices), devices, &numDevices) == EGL_TRUE) { + FF_DEBUG("eglQueryDevicesEXT() returned %d device(s)", numDevices); + for (EGLint i = 0; i < numDevices; i++) { + const EGLDeviceEXT device = devices[i]; + if (device == (EGLDeviceEXT) EGL_NO_DEVICE_EXT || device == (EGLDeviceEXT) EGL_BAD_DEVICE_EXT) { + FF_DEBUG("eglQueryDevicesEXT() returned invalid device at index %d", i); + continue; + } + const char* exts = (const char*) ffeglQueryDeviceStringEXT(device, EGL_EXTENSIONS); + FF_DEBUG("eglQueryDeviceStringEXT() returned extensions for device %d: %s", i, exts); + if (exts && ffStrContains(exts, "EGL_MESA_device_software")) { + FF_DEBUG("eglQueryDeviceStringEXT() returned software device at index %d, skipping", i); + continue; + } + + const char* name = ffeglQueryDeviceStringEXT(device, EGL_RENDERER_EXT); + if (!name) { + FF_DEBUG("eglQueryDeviceStringEXT() returned NULL name for device %d, skipping", i); + continue; + } + + FFGPUResult* gpu = FF_LIST_ADD(FFGPUResult, *result); + ffStrbufInitS(&gpu->name, name); + ffStrbufInit(&gpu->vendor); + ffStrbufInitS(&gpu->driver, ffeglQueryDeviceStringEXT(device, EGL_DRIVER_NAME_EXT)); + ffStrbufInitF(&gpu->platformApi, "egl-ext"); + ffStrbufInit(&gpu->memoryType); + gpu->index = FF_GPU_INDEX_UNSET; + gpu->temperature = FF_GPU_TEMP_UNSET; + gpu->coreCount = FF_GPU_CORE_COUNT_UNSET; + gpu->coreUsage = FF_GPU_CORE_USAGE_UNSET; + gpu->type = FF_GPU_TYPE_UNKNOWN; + gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET; + gpu->deviceId = 0; + gpu->frequency = FF_GPU_FREQUENCY_UNSET; + gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET; + + ffeglQueryDeviceBinaryEXT(device, EGL_DEVICE_UUID_EXT, sizeof(gpu->deviceId), &gpu->deviceId, NULL); + + if (!normalizeVendorName(gpu)) { + ffStrbufSetS(&gpu->vendor, ffeglQueryDeviceStringEXT(device, EGL_VENDOR)); + } + + FF_DEBUG("Detected GPU %d: vendor='%s', name='%s', driver='%s', id='%16" PRIX64 "'", i, gpu->vendor.chars, gpu->name.chars, gpu->driver.chars, gpu->deviceId); + } + } else { + FF_DEBUG("eglQueryDevicesEXT() returned EGL_FALSE"); + } + + return NULL; +} + #endif + +#endif + + const char* ffDetectGPU(const FFGPUOptions* options, FFlist* result) { FF_DEBUG("Starting GPU detection with method=%d", (int) options->detectionMethod); @@ -192,6 +293,22 @@ const char* ffDetectGPU(const FFGPUOptions* options, FFlist* result) { opencl->error ?: "none", opencl->gpus.length); } + if (options->detectionMethod <= FF_GPU_DETECTION_METHOD_EGL_EXT) { + #if FF_HAVE_EGL_EXT + FF_DEBUG("Trying EGL_EXT GPU detection fallback"); + const char* error = detectByEglext(result); + if (!error && result->length > 0) { + FF_DEBUG("EGL_EXT GPU detection succeeded with %u GPU(s)", result->length); + return NULL; + } + + FF_DEBUG("EGL_EXT GPU detection did not produce results (error=%s, gpuCount=%u)", + error ?: "none", + result->length); + #else + FF_DEBUG("EGL_EXT GPU detection is unavailable"); + #endif + } if (options->detectionMethod <= FF_GPU_DETECTION_METHOD_OPENGL) { FF_DEBUG("Trying OpenGL GPU detection fallback"); const char* error = detectByOpenGL(result); @@ -206,3 +323,33 @@ const char* ffDetectGPU(const FFGPUOptions* options, FFlist* result) { FF_DEBUG("GPU detection failed in all enabled backends"); return "GPU detection failed"; } + +bool ffGPUFillVendorByDeviceName(FFGPUResult* gpu) { + if (gpu->type != FF_GPU_TYPE_UNKNOWN) { + return true; + } + + FF_DEBUG("Using fallback GPU type detection"); + if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA) { + if (ffStrbufStartsWithIgnCaseS(&gpu->name, "GeForce") || + ffStrbufStartsWithIgnCaseS(&gpu->name, "Quadro") || + ffStrbufStartsWithIgnCaseS(&gpu->name, "Tesla")) { + gpu->type = FF_GPU_TYPE_DISCRETE; + } + } else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_MTHREADS) { + if (ffStrbufStartsWithIgnCaseS(&gpu->name, "MTT ")) { gpu->type = FF_GPU_TYPE_DISCRETE; } + } else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL) { + // 0000:00:02.0 is reserved for Intel integrated graphics + gpu->type = gpu->deviceId == ffGPUPciAddr2Id(0, 0, 2, 0) ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE; + } else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_VMWARE || gpu->vendor.chars == FF_GPU_VENDOR_NAME_PARALLELS) { + // Virtualized GPUs + gpu->type = FF_GPU_TYPE_INTEGRATED; + } + + if (gpu->type != FF_GPU_TYPE_UNKNOWN) { + FF_DEBUG("Determined GPU type based on vendor (%s) and name: %u", gpu->vendor.chars, gpu->type); + return true; + } + + return false; +} diff --git a/src/detection/gpu/gpu.h b/src/detection/gpu/gpu.h index 10bd02b3f4..e993b512e5 100644 --- a/src/detection/gpu/gpu.h +++ b/src/detection/gpu/gpu.h @@ -7,6 +7,7 @@ #define FF_GPU_CORE_COUNT_UNSET -1 #define FF_GPU_VMEM_SIZE_UNSET ((uint64_t) -1) #define FF_GPU_FREQUENCY_UNSET 0 +#define FF_GPU_PCIE_SPEED_UNSET 0 #define FF_GPU_CORE_USAGE_UNSET (-DBL_MAX) #define FF_GPU_INDEX_UNSET ((uint32_t) -1) @@ -34,6 +35,11 @@ typedef struct FFGPUMemory { uint64_t used; } FFGPUMemory; +typedef struct FFGPUPcieSpeed { + uint16_t gen; + uint16_t lanes; +} FFGPUPcieSpeed; + typedef struct FFGPUResult { uint32_t index; FFGPUType type; @@ -46,6 +52,13 @@ typedef struct FFGPUResult { double coreUsage; int32_t coreCount; uint32_t frequency; // Maximum time clock frequency in MHz + union { + struct { + FFGPUPcieSpeed psMax; + FFGPUPcieSpeed psCurr; + }; + uint64_t pcieSpeed; + }; FFGPUMemory dedicated; FFGPUMemory shared; uint64_t deviceId; @@ -67,14 +80,17 @@ typedef struct FFGpuDriverPciBusId { void ffGPUFillVendorAndName(uint8_t subclass, uint16_t vendor, uint16_t device, FFGPUResult* gpu); void ffGPUQueryAmdGpuName(uint16_t deviceId, uint8_t revisionId, FFGPUResult* gpu); - #if FF_HAVE_DRM + #if FF_HAVE_DRM || __has_include() const char* ffDrmDetectRadeon(const FFGPUOptions* options, FFGPUResult* gpu, const char* renderPath); const char* ffDrmDetectAmdgpu(const FFGPUOptions* options, FFGPUResult* gpu, const char* renderPath); const char* ffDrmDetectI915(FFGPUResult* gpu, int fd); const char* ffDrmDetectXe(FFGPUResult* gpu, int fd); const char* ffDrmDetectAsahi(FFGPUResult* gpu, int fd); const char* ffDrmDetectNouveau(FFGPUResult* gpu, int fd); - #endif // FF_HAVE_DRM + #if __FreeBSD__ || __OpenBSD__ // DRM is not available on NetBSD +const char* ffGPUDetectByDrmBSD(const FFGPUOptions* options, FFlist* gpus); + #endif + #endif // FF_HAVE_DRM || __has_include() const char* ffGPUDetectDriverSpecific(const FFGPUOptions* options, FFGPUResult* gpu, FFGpuDriverPciBusId pciBusId); #endif // defined(XXX) @@ -87,3 +103,5 @@ static inline uint64_t ffGPUGeneral2Id(uint64_t originalId) { // Note: originalId may already have the MSB set return (1ULL << 63) | originalId; } + +bool ffGPUFillVendorByDeviceName(FFGPUResult* gpu); diff --git a/src/detection/gpu/gpu_amd.c b/src/detection/gpu/gpu_amd.c index f396def1d7..4a8134cf82 100644 --- a/src/detection/gpu/gpu_amd.c +++ b/src/detection/gpu/gpu_amd.c @@ -52,6 +52,7 @@ struct FFAdlData { FF_LIBRARY_SYMBOL(ADL2_Adapter_MemoryInfo2_Get) FF_LIBRARY_SYMBOL(ADL2_Adapter_DedicatedVRAMUsage_Get) FF_LIBRARY_SYMBOL(ADL2_Adapter_ASICFamilyType_Get) + FF_LIBRARY_SYMBOL(ADL2_Adapter_ChipSetInfo_Get) FF_LIBRARY_SYMBOL(ADL2_Overdrive_Caps) FF_LIBRARY_SYMBOL(ADL2_OverdriveN_CapabilitiesX2_Get) FF_LIBRARY_SYMBOL(ADL2_OverdriveN_SystemClocksX2_Get) @@ -89,6 +90,7 @@ const char* ffDetectAmdGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResu FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_MemoryInfo2_Get) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_DedicatedVRAMUsage_Get) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_ASICFamilyType_Get) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_ChipSetInfo_Get) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Overdrive_Caps) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_OverdriveN_CapabilitiesX2_Get) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_OverdriveN_SystemClocksX2_Get) @@ -233,6 +235,40 @@ const char* ffDetectAmdGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResu FF_DEBUG("Setting adapter name: %s; UDID: %s, Present: %d, Exist: %d", device->strAdapterName, device->strUDID, device->iPresent, device->iExist); } + if (result.psMax || result.psCurr) { + ADLChipSetInfo chipSetInfo; + int status = adlData.ffADL2_Adapter_ChipSetInfo_Get(adlData.apiHandle, device->iAdapterIndex, &chipSetInfo); + FF_DEBUG("ADL2_Adapter_ChipSetInfo_Get returned %s (%d)", ffAdlStatusToString(status), status); + + if (status == ADL_OK) { + FF_DEBUG("Chipset info - iBusSpeedType: %d, iMaxPCIELaneWidth: %d", chipSetInfo.iBusSpeedType, chipSetInfo.iMaxPCIELaneWidth); + if (result.psMax) { + if (chipSetInfo.iBusSpeedType >= 2) { + result.psMax->gen = (uint16_t) (chipSetInfo.iBusSpeedType - 2); + FF_DEBUG("Got PCIe Max Gen: %u", result.psMax->gen); + } + if (chipSetInfo.iMaxPCIELaneWidth > 0) { + result.psMax->lanes = (uint16_t) chipSetInfo.iMaxPCIELaneWidth; + FF_DEBUG("Got PCIe Max Lanes: %u", result.psMax->lanes); + } + } + + FF_DEBUG("Chipset info - iBusType: %d, iCurrentPCIELaneWidth: %d", chipSetInfo.iBusType, chipSetInfo.iCurrentPCIELaneWidth); + if (result.psCurr) { + if (chipSetInfo.iBusType >= 2) { + result.psCurr->gen = (uint16_t) (chipSetInfo.iBusType - 2); + FF_DEBUG("Got PCIe Current Gen: %u", result.psCurr->gen); + } + if (chipSetInfo.iCurrentPCIELaneWidth > 0) { + result.psCurr->lanes = (uint16_t) chipSetInfo.iCurrentPCIELaneWidth; + FF_DEBUG("Got PCIe Current Lanes: %u", result.psCurr->lanes); + } + } + } else { + FF_DEBUG("Failed to get chipset information"); + } + } + int odVersion = 0; { diff --git a/src/detection/gpu/gpu_apple.c b/src/detection/gpu/gpu_apple.c index 3b8de206f3..623f081d8f 100644 --- a/src/detection/gpu/gpu_apple.c +++ b/src/detection/gpu/gpu_apple.c @@ -118,6 +118,7 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus) { gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET; gpu->type = FF_GPU_TYPE_UNKNOWN; gpu->frequency = FF_GPU_FREQUENCY_UNSET; + gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET; IORegistryEntryGetRegistryEntryID(registryEntry, &gpu->deviceId); ffStrbufInitStatic(&gpu->platformApi, "IOKit"); diff --git a/src/detection/gpu/gpu_bsd.c b/src/detection/gpu/gpu_bsd.c index ae29f46c49..607cfff3f9 100644 --- a/src/detection/gpu/gpu_bsd.c +++ b/src/detection/gpu/gpu_bsd.c @@ -1,7 +1,7 @@ +#include "gpu.h" #include "gpu_driver_specific.h" #include "common/io.h" -#include "common/mallocHelper.h" #include #include @@ -11,140 +11,6 @@ #include // DragonFly #endif -static void fillGPUTypeGeneric(FFGPUResult* gpu) { - if (gpu->type == FF_GPU_TYPE_UNKNOWN) { - if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA) { - if (ffStrbufStartsWithIgnCaseS(&gpu->name, "GeForce") || - ffStrbufStartsWithIgnCaseS(&gpu->name, "Quadro") || - ffStrbufStartsWithIgnCaseS(&gpu->name, "Tesla")) { - gpu->type = FF_GPU_TYPE_DISCRETE; - } - } else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_MTHREADS) { - if (ffStrbufStartsWithIgnCaseS(&gpu->name, "MTT ")) { - gpu->type = FF_GPU_TYPE_DISCRETE; - } - } else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL) { - // 0000:00:02.0 is reserved for Intel integrated graphics - gpu->type = gpu->deviceId == ffGPUPciAddr2Id(0, 0, 2, 0) ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE; - } - } -} - -#if FF_HAVE_DRM - #include "common/library.h" - #include "common/strutil.h" - - #include - -static const char* detectByDrm(const FFGPUOptions* options, FFlist* gpus) { - FF_LIBRARY_LOAD_MESSAGE(libdrm, "libdrm" FF_LIBRARY_EXTENSION, 2) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmGetDevices) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmFreeDevices) - - drmDevicePtr devices[64]; - int nDevices = ffdrmGetDevices(devices, ARRAY_SIZE(devices)); - if (nDevices < 0) { - return "drmGetDevices() failed"; - } - - for (int iDev = 0; iDev < nDevices; ++iDev) { - drmDevice* dev = devices[iDev]; - - if (!(dev->available_nodes & (1 << DRM_NODE_PRIMARY))) { - continue; - } - - const char* path = dev->nodes[DRM_NODE_PRIMARY]; - - FFGPUResult* gpu = FF_LIST_ADD(FFGPUResult, *gpus); - ffStrbufInit(&gpu->vendor); - ffStrbufInit(&gpu->name); - ffStrbufInit(&gpu->driver); - ffStrbufInitS(&gpu->platformApi, path); - ffStrbufInit(&gpu->memoryType); - gpu->index = FF_GPU_INDEX_UNSET; - gpu->temperature = FF_GPU_TEMP_UNSET; - gpu->coreCount = FF_GPU_CORE_COUNT_UNSET; - gpu->coreUsage = FF_GPU_CORE_USAGE_UNSET; - gpu->type = FF_GPU_TYPE_UNKNOWN; - gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET; - gpu->deviceId = 0; - gpu->frequency = FF_GPU_FREQUENCY_UNSET; - - switch (dev->bustype) { - case DRM_BUS_PCI: - ffStrbufInitStatic(&gpu->vendor, ffGPUGetVendorString(dev->deviceinfo.pci->vendor_id)); - gpu->deviceId = ffGPUPciAddr2Id(dev->businfo.pci->domain, dev->businfo.pci->bus, dev->businfo.pci->dev, dev->businfo.pci->func); - break; - case DRM_BUS_HOST1X: - ffStrbufSetS(&gpu->name, dev->deviceinfo.host1x->compatible[0]); - gpu->type = FF_GPU_TYPE_INTEGRATED; - break; - case DRM_BUS_PLATFORM: - ffStrbufSetS(&gpu->name, dev->deviceinfo.platform->compatible[0]); - gpu->type = FF_GPU_TYPE_INTEGRATED; - break; - case DRM_BUS_USB: - ffStrbufSetF(&gpu->name, "USB Device (%u-%u)", dev->deviceinfo.usb->vendor, dev->deviceinfo.usb->product); - gpu->type = FF_GPU_TYPE_DISCRETE; - break; - } - - FF_AUTO_CLOSE_FD int fd = open(path, O_RDONLY | O_CLOEXEC); - if (fd < 0) { - continue; - } - - char driverName[64]; - driverName[0] = '\0'; - struct drm_version ver = { - .name = driverName, - .name_len = ARRAY_SIZE(driverName), - }; - if (ioctl(fd, DRM_IOCTL_VERSION, &ver) == 0) { - driverName[ver.name_len] = '\0'; - ffStrbufSetF(&gpu->driver, "%s %d.%d.%d", ver.name, ver.version_major, ver.version_minor, ver.version_patchlevel); - } - - if (ffStrStartsWith(driverName, "i915")) { - ffDrmDetectI915(gpu, fd); - } else if (ffStrStartsWith(driverName, "amdgpu")) { - ffDrmDetectAmdgpu(options, gpu, dev->nodes[DRM_NODE_RENDER]); - } else if (ffStrStartsWith(driverName, "radeon")) { - ffDrmDetectRadeon(options, gpu, dev->nodes[DRM_NODE_RENDER]); - } else if (ffStrStartsWith(driverName, "xe")) { - ffDrmDetectXe(gpu, fd); - } else if (ffStrStartsWith(driverName, "asahi")) { - ffDrmDetectAsahi(gpu, fd); - } else if (ffStrStartsWith(driverName, "nouveau")) { - ffDrmDetectNouveau(gpu, fd); - } else if (dev->bustype == DRM_BUS_PCI) { - ffGPUDetectDriverSpecific(options, gpu, (FFGpuDriverPciBusId) { - .domain = (uint32_t) dev->businfo.pci->domain, - .bus = dev->businfo.pci->bus, - .device = dev->businfo.pci->dev, - .func = dev->businfo.pci->func, - }); - } - - if (gpu->name.length == 0) { - if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) { - ffGPUQueryAmdGpuName(dev->deviceinfo.pci->device_id, dev->deviceinfo.pci->revision_id, gpu); - } - if (gpu->name.length == 0) { - ffGPUFillVendorAndName(0, dev->deviceinfo.pci->vendor_id, dev->deviceinfo.pci->device_id, gpu); - } - } - - fillGPUTypeGeneric(gpu); - } - - ffdrmFreeDevices(devices, nDevices); - - return NULL; -} -#endif - static const char* detectByPci(const FFGPUOptions* options, FFlist* gpus) { FF_AUTO_CLOSE_FD int fd = open("/dev/pci", O_RDONLY | O_CLOEXEC); if (fd < 0) { @@ -193,6 +59,7 @@ static const char* detectByPci(const FFGPUOptions* options, FFlist* gpus) { gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET; gpu->deviceId = ffGPUPciAddr2Id(pc->pc_sel.pc_domain, pc->pc_sel.pc_bus, pc->pc_sel.pc_dev, pc->pc_sel.pc_func); gpu->frequency = FF_GPU_FREQUENCY_UNSET; + gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET; ffGPUDetectDriverSpecific(options, gpu, (FFGpuDriverPciBusId) { .domain = (uint32_t) pc->pc_sel.pc_domain, @@ -210,7 +77,7 @@ static const char* detectByPci(const FFGPUOptions* options, FFlist* gpus) { } } - fillGPUTypeGeneric(gpu); + ffGPUFillVendorByDeviceName(gpu); } return NULL; @@ -219,7 +86,7 @@ static const char* detectByPci(const FFGPUOptions* options, FFlist* gpus) { const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus) { #if FF_HAVE_DRM if (options->detectionMethod == FF_GPU_DETECTION_METHOD_AUTO) { - detectByDrm(options, gpus); + ffGPUDetectByDrmBSD(options, gpus); if (gpus->length > 0) { return NULL; } diff --git a/src/detection/gpu/gpu_bsddrm.c b/src/detection/gpu/gpu_bsddrm.c new file mode 100644 index 0000000000..7f3a16a000 --- /dev/null +++ b/src/detection/gpu/gpu_bsddrm.c @@ -0,0 +1,204 @@ +#if FF_HAVE_DRM + + #include "gpu.h" + #include "common/strutil.h" + #include "common/io.h" + + #include + #include + #if __FreeBSD__ + #include + #include + #include + #include + #if __has_include() + #include // FreeBSD + #else + #include // DragonFly + #endif + #endif + +// https://github.com/freebsd/drm-kmod/blob/8fea1f06b3ac3fa24217e24ba7b2133abad705a9/include/uapi/drm/drm.h#L1095 +struct drm_pciinfo { + uint16_t domain; + uint8_t bus; + uint8_t dev; + uint8_t func; + uint16_t vendor_id; + uint16_t device_id; + uint16_t subvendor_id; + uint16_t subdevice_id; + uint8_t revision_id; +}; + + #define DRM_IOCTL_GET_PCIINFO DRM_IOR(0x15, struct drm_pciinfo) + +static const char* drmGetPciinfo(int drmfd, const char* drmId, struct drm_pciinfo* result) { + #if !__FreeBSD__ + FF_UNUSED(drmId); + if (ioctl(drmfd, DRM_IOCTL_GET_PCIINFO, result) < 0) { + return "ioctl(DRM_IOCTL_GET_PCIINFO) failed"; + } + #else + FF_UNUSED(drmfd); + char requestBuf[64]; + snprintf(requestBuf, ARRAY_SIZE(requestBuf), "hw.dri.%s.busid", drmId); + char pciidBuf[64]; + size_t pciidLen = ARRAY_SIZE(pciidBuf); + if (sysctlbyname(requestBuf, pciidBuf, &pciidLen, NULL, 0) < 0) { + return "sysctlbyname(hw.dri.%s.busid) failed"; + } + // hw.dri.0.busid: pci:0000:01:00.0 + struct pci_match_conf match = { + .pc_class = PCIC_DISPLAY, + .flags = PCI_GETCONF_MATCH_CLASS | PCI_GETCONF_MATCH_DOMAIN | PCI_GETCONF_MATCH_BUS | PCI_GETCONF_MATCH_DEV | PCI_GETCONF_MATCH_FUNC, + }; + if (sscanf(pciidBuf, "pci:%" SCNx32 ":%" SCNx8 ":%" SCNx8 ".%" SCNx8, &match.pc_sel.pc_domain, &match.pc_sel.pc_bus, &match.pc_sel.pc_dev, &match.pc_sel.pc_func) != 4) { + return "Invalid PCI busid found"; + } + + FF_AUTO_CLOSE_FD int pcifd = open("/dev/pci", O_RDONLY | O_CLOEXEC); + if (pcifd < 0) { + return "open(\"/dev/pci\", O_RDONLY | O_CLOEXEC, 0) failed"; + } + + struct pci_conf conf; + struct pci_conf_io pcio = { + .pat_buf_len = sizeof(match), + .num_patterns = 1, + .patterns = &match, + .match_buf_len = sizeof(conf), + .matches = &conf, + }; + + if (ioctl(pcifd, PCIOCGETCONF, &pcio) < 0) { + perror("ioctl"); + return "ioctl(pcifd, PCIOCGETCONF, &pc) failed"; + } + + if (pcio.status == PCI_GETCONF_ERROR) { + return "ioctl(pcifd, PCIOCGETCONF, &pc) returned error"; + } + + if (pcio.num_matches != 1) { + return "ioctl(pcifd, PCIOCGETCONF, &pc) returned no results"; + } + + *result = (struct drm_pciinfo){ + .domain = (uint16_t) conf.pc_sel.pc_domain, + .bus = conf.pc_sel.pc_bus, + .dev = conf.pc_sel.pc_dev, + .func = conf.pc_sel.pc_func, + .vendor_id = conf.pc_vendor, + .device_id = conf.pc_device, + .subvendor_id = conf.pc_subvendor, + .subdevice_id = conf.pc_subdevice, + .revision_id = conf.pc_revid, + }; + + // This sysctl can also be useful + // dev.drm.0.PCI_ID: 10de:2782 + #endif + + return NULL; +} + +const char* ffGPUDetectByDrmBSD(const FFGPUOptions* options, FFlist* gpus) { + FF_AUTO_CLOSE_DIR DIR* dirp = opendir("/dev/dri/"); + if (dirp == NULL) { + return "opendir(/dev/dri/) failed"; + } + int drifd = dirfd(dirp); + + struct dirent* entry; + while ((entry = readdir(dirp)) != NULL) { + if (entry->d_name[0] == '.' || !ffStrStartsWith(entry->d_name, "card")) { + continue; + } + + FF_AUTO_CLOSE_FD int fd = openat(drifd, entry->d_name, O_RDWR | O_CLOEXEC); + if (fd < 0) { + continue; + } + + // Currently, DRM_BUS_PCI is the only bus type supported by drm-kmod on BSD (hard-coded in libdrm source tree) + struct drm_pciinfo pciInfo; + if (drmGetPciinfo(fd, entry->d_name + strlen("card"), &pciInfo) != NULL) { + continue; + } + + FFGPUResult* gpu = FF_LIST_ADD(FFGPUResult, *gpus); + ffStrbufInitStatic(&gpu->vendor, ffGPUGetVendorString(pciInfo.vendor_id)); + ffStrbufInit(&gpu->name); + ffStrbufInit(&gpu->driver); + ffStrbufInitF(&gpu->platformApi, "/dev/dri/%s", entry->d_name); + ffStrbufInit(&gpu->memoryType); + gpu->index = FF_GPU_INDEX_UNSET; + gpu->temperature = FF_GPU_TEMP_UNSET; + gpu->coreCount = FF_GPU_CORE_COUNT_UNSET; + gpu->coreUsage = FF_GPU_CORE_USAGE_UNSET; + gpu->type = FF_GPU_TYPE_UNKNOWN; + gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET; + gpu->deviceId = ffGPUPciAddr2Id(pciInfo.domain, pciInfo.bus, pciInfo.dev, pciInfo.func); + gpu->frequency = FF_GPU_FREQUENCY_UNSET; + gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET; + + char driverName[64]; + driverName[0] = '\0'; + struct drm_version ver = { + .name = driverName, + .name_len = ARRAY_SIZE(driverName) - 1, + }; + if (ioctl(fd, DRM_IOCTL_VERSION, &ver) == 0) { + driverName[ver.name_len] = '\0'; + ffStrbufSetF(&gpu->driver, "%s %d.%d.%d", ver.name, ver.version_major, ver.version_minor, ver.version_patchlevel); + } + + if (ffStrStartsWith(driverName, "i915")) { + ffDrmDetectI915(gpu, fd); + } else if (ffStrStartsWith(driverName, "amdgpu")) { + uint32_t primaryNodeId = (uint32_t) strtoul(entry->d_name + strlen("card"), NULL, 10); + FF_STRBUF_AUTO_DESTROY renderNode = ffStrbufCreateF("/dev/dri/renderD%d", primaryNodeId + 128); + ffDrmDetectAmdgpu(options, gpu, renderNode.chars); + } else if (ffStrStartsWith(driverName, "radeon")) { + uint32_t primaryNodeId = (uint32_t) strtoul(entry->d_name + strlen("card"), NULL, 10); + FF_STRBUF_AUTO_DESTROY renderNode = ffStrbufCreateF("/dev/dri/renderD%d", primaryNodeId + 128); + ffDrmDetectRadeon(options, gpu, renderNode.chars); + } else if (ffStrStartsWith(driverName, "xe")) { + ffDrmDetectXe(gpu, fd); + } else if (ffStrStartsWith(driverName, "asahi")) { + ffDrmDetectAsahi(gpu, fd); + } else if (ffStrStartsWith(driverName, "nouveau")) { + ffDrmDetectNouveau(gpu, fd); + } else { + ffGPUDetectDriverSpecific(options, gpu, (FFGpuDriverPciBusId){ + .domain = pciInfo.domain, + .bus = pciInfo.bus, + .device = pciInfo.dev, + .func = pciInfo.func, + }); + } + + if (gpu->name.length == 0) { + if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) { + ffGPUQueryAmdGpuName(pciInfo.device_id, pciInfo.revision_id, gpu); + } + if (gpu->name.length == 0) { + ffGPUFillVendorAndName(0, pciInfo.vendor_id, pciInfo.device_id, gpu); + } + } + + ffGPUFillVendorByDeviceName(gpu); + } + + return NULL; +} + +#else + +const char* ffGPUDetectByDrmBSD(const FFGPUOptions* options, FFlist* gpus) { + FF_UNUSED(options, gpus); + return "Fastfetch was built without libdrm support"; +} + +#endif // __FreeBSD__ || __OpenBSD__ diff --git a/src/detection/gpu/gpu_driver_specific.h b/src/detection/gpu/gpu_driver_specific.h index 3ddfb69b74..807a0eb6ef 100644 --- a/src/detection/gpu/gpu_driver_specific.h +++ b/src/detection/gpu/gpu_driver_specific.h @@ -36,6 +36,8 @@ typedef struct FFGpuDriverResult { FFGPUType* type; uint32_t* frequency; FFstrbuf* name; + FFGPUPcieSpeed* psMax; + FFGPUPcieSpeed* psCurr; } FFGpuDriverResult; const char* ffDetectNvidiaGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResult result, const char* soName); diff --git a/src/detection/gpu/gpu_drm.c b/src/detection/gpu/gpu_drm.c index 3a7d381a3f..ecc0e28f7f 100644 --- a/src/detection/gpu/gpu_drm.c +++ b/src/detection/gpu/gpu_drm.c @@ -1,19 +1,26 @@ #include "gpu.h" -#if FF_HAVE_DRM - #include +#if FF_HAVE_DRM || __has_include() #include #include #include "common/io.h" - #include "common/library.h" #include "common/mallocHelper.h" - #include "common/strutil.h" + #if FF_HAVE_DRM + #include + #include + #include + #include + #else + #define FF_HAVE_DRM 1 + #include + #include + #include + #include + #endif #include "intel_drm.h" #include "asahi_drm.h" - #include - #include const char* ffDrmDetectRadeon(const FFGPUOptions* options, FFGPUResult* gpu, const char* renderPath) { FF_AUTO_CLOSE_FD int fd = open(renderPath, O_RDONLY | O_CLOEXEC); @@ -76,52 +83,50 @@ const char* ffDrmDetectRadeon(const FFGPUOptions* options, FFGPUResult* gpu, con return NULL; } - #ifdef FF_HAVE_DRM_AMDGPU - #include - #include - const char* ffDrmDetectAmdgpu(const FFGPUOptions* options, FFGPUResult* gpu, const char* renderPath) { - #if FF_HAVE_DRM_AMDGPU - FF_LIBRARY_LOAD_MESSAGE(libdrm, "libdrm_amdgpu" FF_LIBRARY_EXTENSION, 1) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_device_initialize) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_get_marketing_name) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_gpu_info) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_sensor_info) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_query_heap_info) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, amdgpu_device_deinitialize) - FF_AUTO_CLOSE_FD int fd = open(renderPath, O_RDONLY | O_CLOEXEC); if (fd < 0) { return "Failed to open DRM render device"; } - amdgpu_device_handle handle; - uint32_t majorVersion, minorVersion; - if (ffamdgpu_device_initialize(fd, &majorVersion, &minorVersion, &handle) < 0) { - return "Failed to initialize AMDGPU device"; - } - uint32_t value; if (options->temp) { - if (ffamdgpu_query_sensor_info(handle, AMDGPU_INFO_SENSOR_GPU_TEMP, sizeof(value), &value) >= 0) { + if (ioctl(fd, DRM_IOCTL_AMDGPU_INFO, + &(struct drm_amdgpu_info) { + .return_pointer = (uintptr_t) &value, + .return_size = sizeof(value), + .query = AMDGPU_INFO_SENSOR, + .query_hw_ip.type = AMDGPU_INFO_SENSOR_GPU_TEMP, + }) >= 0 && value != 0) { gpu->temperature = value / 1000.; } } - ffStrbufSetS(&gpu->name, ffamdgpu_get_marketing_name(handle)); - - struct amdgpu_gpu_info gpuInfo; - if (ffamdgpu_query_gpu_info(handle, &gpuInfo) >= 0) { - gpu->coreCount = (int32_t) gpuInfo.cu_active_number; - gpu->frequency = (uint32_t) (gpuInfo.max_engine_clk / 1000u); + struct drm_amdgpu_info_device devInfo; + if (ioctl(fd, DRM_IOCTL_AMDGPU_INFO, + &(struct drm_amdgpu_info) { + .return_pointer = (uintptr_t) &devInfo, + .return_size = sizeof(devInfo), + .query = AMDGPU_INFO_DEV_INFO, + }) >= 0) { + gpu->coreCount = (int32_t) devInfo.cu_active_number; + gpu->frequency = (uint32_t) (devInfo.max_engine_clock / 1000u); gpu->index = FF_GPU_INDEX_UNSET; - gpu->type = gpuInfo.ids_flags & AMDGPU_IDS_FLAGS_FUSION ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE; - #define FF_VRAM_CASE(name, value) \ - case value /* AMDGPU_VRAM_TYPE_ ## name */: \ + gpu->type = devInfo.ids_flags & AMDGPU_IDS_FLAGS_FUSION ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE; + // Was `_pad`. Introduced in commit https://github.com/sailfishos-mirror/drm/commit/22b698a5990292bce0eeb2782754d1eba3fe7a2e + #ifdef AMDGPU_FAMILY_GC_11_0_0 + gpu->psMax.gen = (uint16_t) devInfo.pcie_gen; + gpu->psMax.lanes = (uint16_t) devInfo.pcie_num_lanes; + #else + gpu->psMax.gen = (uint16_t) devInfo._pad; + gpu->psMax.lanes = (uint16_t) devInfo._pad1; + #endif + #define FF_VRAM_CASE(name, value) \ + case value /* AMDGPU_VRAM_TYPE_ ## name */: \ ffStrbufSetStatic(&gpu->memoryType, #name); \ break - switch (gpuInfo.vram_type) { + switch (devInfo.vram_type) { FF_VRAM_CASE(UNKNOWN, 0); FF_VRAM_CASE(GDDR1, 1); FF_VRAM_CASE(DDR2, 2); @@ -135,35 +140,39 @@ const char* ffDrmDetectAmdgpu(const FFGPUOptions* options, FFGPUResult* gpu, con FF_VRAM_CASE(DDR5, 10); FF_VRAM_CASE(LPDDR4, 11); FF_VRAM_CASE(LPDDR5, 12); + FF_VRAM_CASE(HBM3E, 13); + FF_VRAM_CASE(HBM4, 14); default: - ffStrbufAppendF(&gpu->memoryType, "Unknown (%u)", gpuInfo.vram_type); + ffStrbufAppendF(&gpu->memoryType, "Unknown (%u)", devInfo.vram_type); break; } + } - struct amdgpu_heap_info heapInfo; - if (ffamdgpu_query_heap_info(handle, AMDGPU_GEM_DOMAIN_VRAM, 0, &heapInfo) >= 0) { - gpu->dedicated.total = heapInfo.heap_size; - gpu->dedicated.used = heapInfo.heap_usage; - } - if (ffamdgpu_query_heap_info(handle, AMDGPU_GEM_DOMAIN_GTT, 0, &heapInfo) >= 0) { - gpu->shared.total = heapInfo.heap_size; - gpu->shared.used = heapInfo.heap_usage; - } + struct drm_amdgpu_memory_info memInfo; + if (ioctl(fd, DRM_IOCTL_AMDGPU_INFO, + &(struct drm_amdgpu_info) { + .return_pointer = (uintptr_t) &memInfo, + .return_size = sizeof(memInfo), + .query = AMDGPU_INFO_MEMORY, + }) >= 0) { + gpu->dedicated.total = memInfo.vram.total_heap_size; + gpu->dedicated.used = memInfo.vram.heap_usage; + gpu->shared.total = memInfo.gtt.total_heap_size; + gpu->shared.used = memInfo.gtt.heap_usage; } - if (ffamdgpu_query_sensor_info(handle, AMDGPU_INFO_SENSOR_GPU_LOAD, sizeof(value), &value) >= 0) { + if (ioctl(fd, DRM_IOCTL_AMDGPU_INFO, + &(struct drm_amdgpu_info) { + .return_pointer = (uintptr_t) &value, + .return_size = sizeof(value), + .query = AMDGPU_INFO_SENSOR, + .query_hw_ip.type = AMDGPU_INFO_SENSOR_GPU_LOAD, + }) >= 0) { gpu->coreUsage = value; } - ffamdgpu_device_deinitialize(handle); - return NULL; - #else - FF_UNUSED(options, gpu, renderPath); - return "Fastfetch is compiled without libdrm support"; - #endif } - #endif const char* ffDrmDetectI915(FFGPUResult* gpu, int fd) { { @@ -356,6 +365,7 @@ const char* ffDrmDetectNouveau(FFGPUResult* gpu, int fd) { #include "gpu_driver_specific.h" const char* ffGPUDetectDriverSpecific(const FFGPUOptions* options, FFGPUResult* gpu, FFGpuDriverPciBusId pciBusId) { +#if !__OpenBSD__ __typeof__(&ffDetectNvidiaGpuInfo) detectFn; const char* soName; if (getDriverSpecificDetectionFn(gpu->vendor.chars, &detectFn, &soName) && (options->temp || options->driverSpecific)) { @@ -367,14 +377,19 @@ const char* ffGPUDetectDriverSpecific(const FFGPUOptions* options, FFGPUResult* .index = &gpu->index, .temp = options->temp ? &gpu->temperature : NULL, .memory = options->driverSpecific ? &gpu->dedicated : NULL, + .sharedMemory = options->driverSpecific ? &gpu->shared : NULL, + .memoryType = options->driverSpecific ? &gpu->memoryType : NULL, .coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL, .coreUsage = options->driverSpecific ? &gpu->coreUsage : NULL, .type = &gpu->type, .frequency = options->driverSpecific ? &gpu->frequency : NULL, .name = &gpu->name, + .psCurr = options->driverSpecific ? &gpu->psCurr : NULL, + .psMax = options->driverSpecific ? &gpu->psMax : NULL, }, soName); } +#endif return "No driver-specific detection function found for the GPU vendor"; } diff --git a/src/detection/gpu/gpu_gnu.c b/src/detection/gpu/gpu_gnu.c index 27c774b203..30cadf81b3 100644 --- a/src/detection/gpu/gpu_gnu.c +++ b/src/detection/gpu/gpu_gnu.c @@ -130,6 +130,7 @@ const char* ffDetectGPUImpl(FF_A_UNUSED const FFGPUOptions* options, FFlist* gpu gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET; gpu->deviceId = ffGPUPciAddr2Id(0, pciBus, pciDev, pciFunc); gpu->frequency = FF_GPU_FREQUENCY_UNSET; + gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET; if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) { ffGPUQueryAmdGpuName(deviceId, revision, gpu); diff --git a/src/detection/gpu/gpu_haiku.c b/src/detection/gpu/gpu_haiku.c index f75f03980f..20a4ae5f6c 100644 --- a/src/detection/gpu/gpu_haiku.c +++ b/src/detection/gpu/gpu_haiku.c @@ -37,6 +37,7 @@ const char* ffDetectGPUImpl(FF_A_UNUSED const FFGPUOptions* options, FFlist* gpu gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET; gpu->deviceId = ffGPUPciAddr2Id(0, dev.bus, dev.device, dev.function); gpu->frequency = FF_GPU_FREQUENCY_UNSET; + gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET; if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) { ffGPUQueryAmdGpuName(dev.device_id, dev.revision, gpu); diff --git a/src/detection/gpu/gpu_intel.c b/src/detection/gpu/gpu_intel.c index 7d94c802a2..474f798398 100644 --- a/src/detection/gpu/gpu_intel.c +++ b/src/detection/gpu/gpu_intel.c @@ -16,6 +16,8 @@ struct FFIgclData { FF_LIBRARY_SYMBOL(ctlMemoryGetState) FF_LIBRARY_SYMBOL(ctlEnumFrequencyDomains) FF_LIBRARY_SYMBOL(ctlFrequencyGetProperties) + FF_LIBRARY_SYMBOL(ctlPciGetProperties) + FF_LIBRARY_SYMBOL(ctlPciGetState) bool inited; ctl_api_handle_t apiHandle; @@ -43,6 +45,8 @@ const char* ffDetectIntelGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverRe FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlMemoryGetState) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlEnumFrequencyDomains) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlFrequencyGetProperties) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlPciGetProperties) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libigcl, igclData, ctlPciGetState) if (ffctlInit(&(ctl_init_args_t) { .AppVersion = CTL_IMPL_VERSION, @@ -227,5 +231,28 @@ const char* ffDetectIntelGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverRe ffStrbufSetS(result.name, properties.name); } + if (result.psMax) { + ctl_pci_properties_t pciProps = { .Size = sizeof(pciProps), .Version = 0 }; + if (igclData.ffctlPciGetProperties(device, &pciProps) == CTL_RESULT_SUCCESS) { + if (pciProps.maxSpeed.gen > 0) { + result.psMax->gen = (uint16_t) pciProps.maxSpeed.gen; + } + if (pciProps.maxSpeed.width > 0) { + result.psMax->lanes = (uint16_t) pciProps.maxSpeed.width; + } + } + } + if (result.psCurr) { + ctl_pci_state_t pciState = { .Size = sizeof(pciState), .Version = 0 }; + if (igclData.ffctlPciGetState(device, &pciState) == CTL_RESULT_SUCCESS) { + if (pciState.speed.gen > 0) { + result.psCurr->gen = (uint16_t) pciState.speed.gen; + } + if (pciState.speed.width > 0) { + result.psCurr->lanes = (uint16_t) pciState.speed.width; + } + } + } + return NULL; } diff --git a/src/detection/gpu/gpu_linux.c b/src/detection/gpu/gpu_linux.c index 3aaa09cb03..8cadb9e31e 100644 --- a/src/detection/gpu/gpu_linux.c +++ b/src/detection/gpu/gpu_linux.c @@ -1,40 +1,12 @@ #include "detection/gpu/gpu.h" -#include "detection/vulkan/vulkan.h" -#include "detection/cpu/cpu.h" -#include "detection/gpu/gpu_driver_specific.h" #include "common/io.h" -#include "common/library.h" #include "common/FFstrbuf.h" #include "common/strutil.h" -#include "common/mallocHelper.h" #include "modules/gpu/option.h" #include #include -#ifdef FF_HAVE_DRM_AMDGPU - #include - #include - #include -#endif - -#ifdef FF_HAVE_DRM - #include "intel_drm.h" - #include - #include -#endif - -#if defined(FF_HAVE_DRM) && defined(__aarch64__) - // https://github.com/alyssarosenzweig/linux/blob/agx-uapi-v7/include/uapi/drm/asahi_drm.h - // Found in kernel-headers-6.14.4-400.asahi.fc42.aarch64 - #if __has_include() - #include - #else - #include "asahi_drm.h" - #endif - #define FF_HAVE_DRM_ASAHI 1 -#endif - static bool pciDetectDriver(FFstrbuf* result, FFstrbuf* pciDir, FFstrbuf* buffer, FF_A_UNUSED const char* drmKey) { uint32_t pciDirLength = pciDir->length; ffStrbufAppendS(pciDir, "/driver"); @@ -100,7 +72,6 @@ FF_A_UNUSED static const char* drmFindRenderFromCard(const char* drmCardKey, FFs } static const char* drmDetectAmdSpecific(const FFGPUOptions* options, FFGPUResult* gpu, const char* drmKey, FFstrbuf* buffer) { -#if FF_HAVE_DRM const char* error = drmFindRenderFromCard(drmKey, buffer); if (error) { return error; @@ -108,17 +79,8 @@ static const char* drmDetectAmdSpecific(const FFGPUOptions* options, FFGPUResult if (ffStrbufEqualS(&gpu->driver, "radeon")) { return ffDrmDetectRadeon(options, gpu, buffer->chars); } else { - #if FF_HAVE_DRM_AMDGPU return ffDrmDetectAmdgpu(options, gpu, buffer->chars); - #else - FF_UNUSED(options, gpu, drmKey, buffer); - return "Fastfetch is not compiled with libdrm_amdgpu support"; - #endif - } -#else - FF_UNUSED(options, gpu, drmKey, buffer); - return "Fastfetch is not compiled with drm support"; -#endif + } } static void pciDetectAmdSpecific(const FFGPUOptions* options, FFGPUResult* gpu, FFstrbuf* pciDir, FFstrbuf* buffer) { @@ -246,7 +208,6 @@ static void pciDetectIntelSpecific(const FFGPUOptions* options, FFGPUResult* gpu } static const char* drmDetectIntelSpecific(FFGPUResult* gpu, const char* drmKey, FFstrbuf* buffer) { -#if FF_HAVE_DRM ffStrbufSetS(buffer, "/dev/dri/"); ffStrbufAppendS(buffer, drmKey); FF_AUTO_CLOSE_FD int fd = open(buffer->chars, O_RDONLY | O_CLOEXEC); @@ -260,10 +221,6 @@ static const char* drmDetectIntelSpecific(FFGPUResult* gpu, const char* drmKey, return ffDrmDetectI915(gpu, fd); } return "Unknown Intel GPU driver"; -#else - FF_UNUSED(gpu, drmKey, buffer); - return "Fastfetch is not compiled with drm support"; -#endif } static const char* pciDetectTempGeneral(const FFGPUOptions* options, FFGPUResult* gpu, FFstrbuf* pciDir, FFstrbuf* buffer) { @@ -294,7 +251,6 @@ static const char* pciDetectTempGeneral(const FFGPUOptions* options, FFGPUResult } static const char* drmDetectNouveauSpecific(FFGPUResult* gpu, const char* drmKey, FFstrbuf* buffer) { -#if FF_HAVE_DRM ffStrbufSetS(buffer, "/dev/dri/"); ffStrbufAppendS(buffer, drmKey); FF_AUTO_CLOSE_FD int fd = open(buffer->chars, O_RDONLY | O_CLOEXEC); @@ -303,10 +259,6 @@ static const char* drmDetectNouveauSpecific(FFGPUResult* gpu, const char* drmKey } return ffDrmDetectNouveau(gpu, fd); -#else - FF_UNUSED(gpu, drmKey, buffer); - return "Fastfetch is not compiled with drm support"; -#endif } static const char* pciDetectZxSpecific(const FFGPUOptions* options, FFGPUResult* gpu, FFstrbuf* pciDir, FFstrbuf* buffer) { @@ -351,6 +303,32 @@ static const char* pciDetectZxSpecific(const FFGPUOptions* options, FFGPUResult* return NULL; } +static inline uint16_t pcieLinkSpeedToGen(const FFstrbuf* buffer) { + int64_t speed = ffStrbufToSInt(buffer, FF_GPU_PCIE_SPEED_UNSET); + if (speed >= 64) { + return 6; + } else if (speed >= 32) { + return 5; + } else if (speed >= 16) { + return 4; + } else if (speed >= 8) { + return 3; + } else if (speed >= 5) { + return 2; + } else if (speed >= 2) { // 2.5 + return 1; + } + return FF_GPU_PCIE_SPEED_UNSET; +} + +static inline uint16_t pcieWidthToLanes(const FFstrbuf* buffer) { + int64_t width = ffStrbufToSInt(buffer, FF_GPU_PCIE_SPEED_UNSET); + if (width > 0 && width < 255) { // kernel returns 255 if the value is unknown + return (uint16_t) width; + } + return FF_GPU_PCIE_SPEED_UNSET; +} + static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf* buffer, FFstrbuf* deviceDir, const char* drmKey) { const uint32_t drmDirPathLength = deviceDir->length; uint32_t vendorId, deviceId, subVendorId, subDeviceId; @@ -406,6 +384,7 @@ static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET; gpu->deviceId = ffGPUPciAddr2Id(pciDomain, pciBus, pciDevice, pciFunc); gpu->frequency = FF_GPU_FREQUENCY_UNSET; + gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET; char drmKeyBuffer[8]; if (!drmKey) { @@ -431,6 +410,34 @@ static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf pciDetectDriver(&gpu->driver, deviceDir, buffer, drmKey); ffStrbufSubstrBefore(deviceDir, drmDirPathLength); + ffStrbufAppendS(deviceDir, "/max_link_speed"); + if (ffReadFileBuffer(deviceDir->chars, buffer)) { + gpu->psMax.gen = pcieLinkSpeedToGen(buffer); + } + ffStrbufSubstrBefore(deviceDir, drmDirPathLength); + + if (gpu->psMax.gen != FF_GPU_PCIE_SPEED_UNSET) { + ffStrbufAppendS(deviceDir, "/max_link_width"); + if (ffReadFileBuffer(deviceDir->chars, buffer)) { + gpu->psMax.lanes = pcieWidthToLanes(buffer); + } + ffStrbufSubstrBefore(deviceDir, drmDirPathLength); + } + + ffStrbufAppendS(deviceDir, "/current_link_speed"); + if (ffReadFileBuffer(deviceDir->chars, buffer)) { + gpu->psCurr.gen = pcieLinkSpeedToGen(buffer); + } + ffStrbufSubstrBefore(deviceDir, drmDirPathLength); + + if (gpu->psCurr.gen != FF_GPU_PCIE_SPEED_UNSET) { + ffStrbufAppendS(deviceDir, "/current_link_width"); + if (ffReadFileBuffer(deviceDir->chars, buffer)) { + gpu->psCurr.lanes = pcieWidthToLanes(buffer); + } + ffStrbufSubstrBefore(deviceDir, drmDirPathLength); + } + if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) { bool ok = false; if (drmKey && options->driverSpecific) { @@ -478,24 +485,13 @@ static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf ffGPUFillVendorAndName(subclassId, (uint16_t) vendorId, (uint16_t) deviceId, gpu); } - if (gpu->type == FF_GPU_TYPE_UNKNOWN) { - if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA) { - if (ffStrbufStartsWithIgnCaseS(&gpu->name, "GeForce") || - ffStrbufStartsWithIgnCaseS(&gpu->name, "Quadro") || - ffStrbufStartsWithIgnCaseS(&gpu->name, "Tesla")) { - gpu->type = FF_GPU_TYPE_DISCRETE; - } - } else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_MTHREADS) { - if (ffStrbufStartsWithIgnCaseS(&gpu->name, "MTT ")) { - gpu->type = FF_GPU_TYPE_DISCRETE; - } - } - } + ffGPUFillVendorByDeviceName(gpu); return NULL; } #if __aarch64__ +#include "detection/cpu/cpu.h" FF_A_UNUSED static const char* drmDetectAsahiSpecific(FFGPUResult* gpu, const char* name, FF_A_UNUSED FFstrbuf* buffer, FF_A_UNUSED const char* drmKey) { if (sscanf(name, "agx-t%lu", &gpu->deviceId) == 1) { @@ -503,14 +499,12 @@ FF_A_UNUSED static const char* drmDetectAsahiSpecific(FFGPUResult* gpu, const ch } ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_APPLE); - #if FF_HAVE_DRM_ASAHI ffStrbufSetS(buffer, "/dev/dri/"); ffStrbufAppendS(buffer, drmKey); FF_AUTO_CLOSE_FD int fd = open(buffer->chars, O_RDONLY | O_CLOEXEC); if (fd >= 0) { return ffDrmDetectAsahi(gpu, fd); } - #endif return NULL; } @@ -542,6 +536,7 @@ static const char* detectOf(FFlist* gpus, FFstrbuf* buffer, FFstrbuf* drmDir, co gpu->type = FF_GPU_TYPE_INTEGRATED; gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET; gpu->frequency = FF_GPU_FREQUENCY_UNSET; + gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET; pciDetectDriver(&gpu->driver, drmDir, buffer, drmKey); diff --git a/src/detection/gpu/gpu_nbsd.c b/src/detection/gpu/gpu_nbsd.c index 4f5dab3c92..10b920da93 100644 --- a/src/detection/gpu/gpu_nbsd.c +++ b/src/detection/gpu/gpu_nbsd.c @@ -97,6 +97,7 @@ const char* ffDetectGPUImpl(FF_A_UNUSED const FFGPUOptions* options, FFlist* gpu gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET; gpu->deviceId = ffGPUPciAddr2Id(0, bus, dev, func); gpu->frequency = FF_GPU_FREQUENCY_UNSET; + gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET; if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) { ffGPUQueryAmdGpuName(PCI_PRODUCT(pciid), PCI_REVISION(pciid), gpu); diff --git a/src/detection/gpu/gpu_nvidia.c b/src/detection/gpu/gpu_nvidia.c index 85776dd825..4ec979f6b5 100644 --- a/src/detection/gpu/gpu_nvidia.c +++ b/src/detection/gpu/gpu_nvidia.c @@ -8,12 +8,16 @@ struct FFNvmlData { FF_LIBRARY_SYMBOL(nvmlDeviceGetHandleByIndex_v2) FF_LIBRARY_SYMBOL(nvmlDeviceGetHandleByPciBusId_v2) FF_LIBRARY_SYMBOL(nvmlDeviceGetPciInfo_v3) - FF_LIBRARY_SYMBOL(nvmlDeviceGetTemperature) + FF_LIBRARY_SYMBOL(nvmlDeviceGetTemperatureV) FF_LIBRARY_SYMBOL(nvmlDeviceGetMemoryInfo_v2) FF_LIBRARY_SYMBOL(nvmlDeviceGetMemoryInfo) FF_LIBRARY_SYMBOL(nvmlDeviceGetNumGpuCores) FF_LIBRARY_SYMBOL(nvmlDeviceGetMaxClockInfo) FF_LIBRARY_SYMBOL(nvmlDeviceGetUtilizationRates) + FF_LIBRARY_SYMBOL(nvmlDeviceGetMaxPcieLinkGeneration) + FF_LIBRARY_SYMBOL(nvmlDeviceGetMaxPcieLinkWidth) + FF_LIBRARY_SYMBOL(nvmlDeviceGetCurrPcieLinkGeneration) + FF_LIBRARY_SYMBOL(nvmlDeviceGetCurrPcieLinkWidth) FF_LIBRARY_SYMBOL(nvmlDeviceGetBrand) FF_LIBRARY_SYMBOL(nvmlDeviceGetIndex) FF_LIBRARY_SYMBOL(nvmlDeviceGetName) @@ -154,11 +158,15 @@ const char* ffDetectNvidiaGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverR FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetHandleByIndex_v2) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetHandleByPciBusId_v2) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetPciInfo_v3) - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetTemperature) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetTemperatureV) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetMemoryInfo_v2) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetMemoryInfo) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetNumGpuCores) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetMaxClockInfo) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetMaxPcieLinkGeneration) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetMaxPcieLinkWidth) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetCurrPcieLinkGeneration) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetCurrPcieLinkWidth) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetUtilizationRates) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetBrand) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetIndex) @@ -246,9 +254,12 @@ const char* ffDetectNvidiaGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverR } if (result.temp) { - uint32_t value; - if (nvmlData.ffnvmlDeviceGetTemperature(device, NVML_TEMPERATURE_GPU, &value) == NVML_SUCCESS) { - *result.temp = value; + nvmlTemperature_v1_t temp = { + .version = nvmlTemperature_v1, + .sensorType = NVML_TEMPERATURE_GPU, + }; + if (nvmlData.ffnvmlDeviceGetTemperatureV(device, &temp) == NVML_SUCCESS) { + *result.temp = temp.temperature; } } @@ -288,6 +299,26 @@ const char* ffDetectNvidiaGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverR } } + if (result.psMax) { + unsigned int value; + if (nvmlData.ffnvmlDeviceGetMaxPcieLinkGeneration(device, &value) == NVML_SUCCESS) { + result.psMax->gen = (uint16_t) value; + } + if (nvmlData.ffnvmlDeviceGetMaxPcieLinkWidth(device, &value) == NVML_SUCCESS) { + result.psMax->lanes = (uint16_t) value; + } + } + + if (result.psCurr) { + unsigned int value; + if (nvmlData.ffnvmlDeviceGetCurrPcieLinkGeneration(device, &value) == NVML_SUCCESS) { + result.psCurr->gen = (uint16_t) value; + } + if (nvmlData.ffnvmlDeviceGetCurrPcieLinkWidth(device, &value) == NVML_SUCCESS) { + result.psCurr->lanes = (uint16_t) value; + } + } + return NULL; #else diff --git a/src/detection/gpu/gpu_obsd.c b/src/detection/gpu/gpu_obsd.c index dabadedd14..8d0ee9a31f 100644 --- a/src/detection/gpu/gpu_obsd.c +++ b/src/detection/gpu/gpu_obsd.c @@ -27,7 +27,7 @@ static inline int pciReadConf(int fd, uint8_t bus, uint8_t device, uint8_t func, return 0; } -const char* ffDetectGPUImpl(FF_A_UNUSED const FFGPUOptions* options, FFlist* gpus) { +const char* detectByPci(FF_A_UNUSED const FFGPUOptions* options, FFlist* gpus) { char pciDevPath[] = "/dev/pci0"; FF_AUTO_CLOSE_FD int pcifd = open(pciDevPath, O_RDONLY | O_CLOEXEC); if (pcifd < 0) { @@ -86,6 +86,7 @@ const char* ffDetectGPUImpl(FF_A_UNUSED const FFGPUOptions* options, FFlist* gpu gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET; gpu->deviceId = ffGPUPciAddr2Id(0, bus, dev, func); gpu->frequency = FF_GPU_FREQUENCY_UNSET; + gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET; if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) { ffGPUQueryAmdGpuName(PCI_PRODUCT(pciid), PCI_REVISION(pciid), gpu); @@ -99,3 +100,16 @@ const char* ffDetectGPUImpl(FF_A_UNUSED const FFGPUOptions* options, FFlist* gpu return NULL; } + +const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus) { +#if FF_HAVE_DRM + if (options->detectionMethod == FF_GPU_DETECTION_METHOD_AUTO) { + ffGPUDetectByDrmBSD(options, gpus); + if (gpus->length > 0) { + return NULL; + } + } +#endif + + return detectByPci(options, gpus); +} diff --git a/src/detection/gpu/gpu_pci.c b/src/detection/gpu/gpu_pci.c index 63cd877c7e..c3772fd911 100644 --- a/src/detection/gpu/gpu_pci.c +++ b/src/detection/gpu/gpu_pci.c @@ -2,6 +2,7 @@ #include "common/io.h" #include "common/properties.h" #include "common/memrchr.h" +#include "common/strutil.h" #include #ifdef __FreeBSD__ @@ -22,9 +23,6 @@ #include "fastfetch_amdgpuids.c.inc" #endif -#define FF_STR_INDIR(x) #x -#define FF_STR(x) FF_STR_INDIR(x) - static const FFstrbuf* loadPciIds() { static FFstrbuf pciids; diff --git a/src/detection/gpu/gpu_sunos.c b/src/detection/gpu/gpu_sunos.c index 13d4998154..dbf168c578 100644 --- a/src/detection/gpu/gpu_sunos.c +++ b/src/detection/gpu/gpu_sunos.c @@ -21,6 +21,7 @@ static int walkDevTree(di_node_t node, FF_A_UNUSED di_minor_t minor, FFlist* gpu gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET; gpu->deviceId = strtoul(di_bus_addr(node), NULL, 16); gpu->frequency = FF_GPU_FREQUENCY_UNSET; + gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET; if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_AMD) { int* revId; diff --git a/src/detection/gpu/gpu_windows.c b/src/detection/gpu/gpu_windows.c index 796c1c566d..18f07d2d56 100644 --- a/src/detection/gpu/gpu_windows.c +++ b/src/detection/gpu/gpu_windows.c @@ -11,31 +11,28 @@ #if _WIN32 #include "common/windows/unicode.h" #include "common/windows/registry.h" + #include "common/mallocHelper.h" - #if FF_WIN81_COMPAT - #include "common/mallocHelper.h" - #include - #include - #include + #define INITGUID + #include + #include + #include + #include - #define GUID_DEVCLASS_DISPLAY_STRING L"{4d36e968-e325-11ce-bfc1-08002be10318}" // Found in + #define GUID_DEVCLASS_DISPLAY_STRING L"{4d36e968-e325-11ce-bfc1-08002be10318}" // Found in -static bool queryDeviceIdsFallback(D3DKMT_ADAPTERADDRESS adapterAddress, D3DKMT_DEVICE_IDS* outDeviceIds) { - FF_DEBUG("KMTQAITYPE_PHYSICALADAPTERDEVICEIDS failed. Attempting queryDeviceIdsFallback: bus=%u device=%u function=%u", - adapterAddress.BusNumber, - adapterAddress.DeviceNumber, - adapterAddress.FunctionNumber); - - if (adapterAddress.BusNumber == -1u) { - FF_DEBUG("Invalid adapter address, cannot query device IDs"); - return false; - } +static bool queryPciDeviceInfo(FFGPUResult* gpu, D3DKMT_DEVICE_IDS* outDeviceIds) { + FF_DEBUG("Query PCI device info: %08llX", gpu->deviceId); static FFlist deviceIdsCache; static bool initialized; typedef struct { + uint32_t currentLinkSpeed; + uint32_t currentLinkWidth; + uint32_t maxLinkSpeed; + uint32_t maxLinkWidth; D3DKMT_DEVICE_IDS deviceIds; - D3DKMT_ADAPTERADDRESS adapterAddress; + uint64_t adapterAddress; } CacheEntry; if (!initialized) { @@ -79,34 +76,29 @@ static bool queryDeviceIdsFallback(D3DKMT_ADAPTERADDRESS adapterAddress, D3DKMT_ continue; } - uint32_t pciBus = 0; + CacheEntry* entry = FF_LIST_ADD(CacheEntry, deviceIdsCache); + *entry = (CacheEntry) {}; + + // L"PCI\\VEN_10DE&DEV_2782&SUBSYS_513417AA&REV_A1\\4&3674a6b9&0&0008" + if (swscanf(devId + 4, L"VEN_%x&DEV_%x&SUBSYS_%4x%4x&REV_%x", &entry->deviceIds.VendorID, &entry->deviceIds.DeviceID, &entry->deviceIds.SubSystemID, &entry->deviceIds.SubVendorID, &entry->deviceIds.RevisionID) >= 2) { + FF_DEBUG("Parsed PCI IDs - Vendor: 0x%04x, Device: 0x%04x, SubVendor: 0x%04x, SubSystem: 0x%04x, Rev: 0x%04x", entry->deviceIds.VendorID, entry->deviceIds.DeviceID, entry->deviceIds.SubVendorID, entry->deviceIds.SubSystemID, entry->deviceIds.RevisionID); + // I thought it was DXGKMDT_OPM_BUS_TYPE_PCI, but it turns out to be false + // Who TF knows what 1 actually means. It's just reported by most graphic cards + // And yeah, DXGKMDT_OPM_BUS_TYPE_PCIEXPRESS (3) exists + entry->deviceIds.BusType = 1; + } else { + FF_DEBUG("Failed to parse PCI IDs from device ID string"); + deviceIdsCache.length--; // remove the cache entry since it's not valid + continue; + } + uint32_t pciBus = 0; ULONG pciBufLen = sizeof(pciBus); if (CM_Get_DevNode_Registry_PropertyW(devInst, CM_DRP_BUSNUMBER, NULL, &pciBus, &pciBufLen, 0) == CR_SUCCESS) { uint32_t pciAddr = 0; pciBufLen = sizeof(pciAddr); if (CM_Get_DevNode_Registry_PropertyW(devInst, CM_DRP_ADDRESS, NULL, &pciAddr, &pciBufLen, 0) == CR_SUCCESS) { - CacheEntry* entry = FF_LIST_ADD(CacheEntry, deviceIdsCache); - - entry->deviceIds = (D3DKMT_DEVICE_IDS) {}; - // L"PCI\\VEN_10DE&DEV_2782&SUBSYS_513417AA&REV_A1\\4&3674a6b9&0&0008" - if (swscanf(devId + 4, L"VEN_%x&DEV_%x&SUBSYS_%4x%4x&REV_%x", &entry->deviceIds.VendorID, &entry->deviceIds.DeviceID, &entry->deviceIds.SubSystemID, &entry->deviceIds.SubVendorID, &entry->deviceIds.RevisionID) >= 2) { - FF_DEBUG("Parsed PCI IDs - Vendor: 0x%04x, Device: 0x%04x, SubVendor: 0x%04x, SubSystem: 0x%04x, Rev: 0x%04x", entry->deviceIds.VendorID, entry->deviceIds.DeviceID, entry->deviceIds.SubVendorID, entry->deviceIds.SubSystemID, entry->deviceIds.RevisionID); - // I thought it was DXGKMDT_OPM_BUS_TYPE_PCI, but it turns out to be false - // Who TF knows what 1 actually means. It's just reported by most graphic cards - // And yeah, DXGKMDT_OPM_BUS_TYPE_PCIEXPRESS (3) exists - entry->deviceIds.BusType = 1; - } else { - FF_DEBUG("Failed to parse PCI IDs from device ID string"); - deviceIdsCache.length--; // remove the cache entry since it's not valid - continue; - } - - entry->adapterAddress = (D3DKMT_ADAPTERADDRESS) { - .BusNumber = pciBus, - .DeviceNumber = (pciAddr >> 16) & 0xFFFF, - .FunctionNumber = pciAddr & 0xFFFF, - }; + entry->adapterAddress = ffGPUPciAddr2Id(0, pciBus, (pciAddr >> 16) & 0xFFFF, pciAddr & 0xFFFF); FF_DEBUG("Cached device IDs for PCI bus %u: vendor=0x%04x device=0x%04x", pciBus, entry->deviceIds.VendorID, entry->deviceIds.DeviceID); } else { FF_DEBUG("Failed to get PCI address"); @@ -114,21 +106,65 @@ static bool queryDeviceIdsFallback(D3DKMT_ADAPTERADDRESS adapterAddress, D3DKMT_ } else { FF_DEBUG("Failed to get PCI bus number"); } + + DEVPROPTYPE propType; + + pciBufLen = sizeof(entry->maxLinkSpeed); + // Reports PCEe gen despite the PKEY name + CONFIGRET ret = CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_PciDevice_MaxLinkSpeed, &propType, (PBYTE) &entry->maxLinkSpeed, &pciBufLen, 0); + if (ret == CR_SUCCESS) { + FF_DEBUG("PCIe max GEN: %u", entry->maxLinkSpeed); + } else { + FF_DEBUG("Failed to get PCIe max GEN: %s", ffDebugConfigRet(ret)); + } + + if (entry->maxLinkSpeed != FF_GPU_PCIE_SPEED_UNSET) { + pciBufLen = sizeof(entry->maxLinkWidth); + ret = CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_PciDevice_MaxLinkWidth, &propType, (PBYTE) &entry->maxLinkWidth, &pciBufLen, 0); + if (ret == CR_SUCCESS) { + FF_DEBUG("PCIe max link width: %u", entry->maxLinkWidth); + } else { + FF_DEBUG("Failed to get PCIe max link width: %s", ffDebugConfigRet(ret)); + } + } + + pciBufLen = sizeof(entry->currentLinkSpeed); + ret = CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_PciDevice_CurrentLinkSpeed, &propType, (PBYTE) &entry->currentLinkSpeed, &pciBufLen, 0); + if (ret == CR_SUCCESS) { + FF_DEBUG("PCIe GEN: %u", entry->currentLinkSpeed); + } else { + FF_DEBUG("Failed to get PCIe GEN: %s", ffDebugConfigRet(ret)); + } + + if (entry->currentLinkSpeed != FF_GPU_PCIE_SPEED_UNSET) { + pciBufLen = sizeof(entry->currentLinkWidth); + ret = CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_PciDevice_CurrentLinkWidth, &propType, (PBYTE) &entry->currentLinkWidth, &pciBufLen, 0); + if (ret == CR_SUCCESS) { + FF_DEBUG("PCIe current link width: %u", entry->currentLinkWidth); + } else { + FF_DEBUG("Failed to get PCIe current link width: %s", ffDebugConfigRet(ret)); + } + } } } FF_LIST_FOR_EACH (CacheEntry, entry, deviceIdsCache) { - if (memcmp(&entry->adapterAddress, &adapterAddress, sizeof(adapterAddress)) == 0) { - FF_DEBUG("Cache hit for adapter address: bus=%u device=%u function=%u", adapterAddress.BusNumber, adapterAddress.DeviceNumber, adapterAddress.FunctionNumber); - *outDeviceIds = entry->deviceIds; + if (gpu->deviceId == entry->adapterAddress) { + FF_DEBUG("Cache hit for adapter address: %08llX", gpu->deviceId); + if (outDeviceIds->VendorID != -1u) { + *outDeviceIds = entry->deviceIds; + } + gpu->psMax.gen = (uint16_t) entry->maxLinkSpeed; + gpu->psMax.lanes = (uint16_t) entry->maxLinkWidth; + gpu->psCurr.gen = (uint16_t) entry->currentLinkSpeed; + gpu->psCurr.lanes = (uint16_t) entry->currentLinkWidth; return true; } } - FF_DEBUG("Cache miss for adapter address: bus=%u device=%u function=%u", adapterAddress.BusNumber, adapterAddress.DeviceNumber, adapterAddress.FunctionNumber); + FF_DEBUG("Cache miss for adapter address: %08llX", gpu->deviceId); return false; } - #endif // FF_WIN81_COMPAT static bool queryVendorNameViaRegistry(FFstrbuf* vendor, D3DKMT_HANDLE hAdapter) { // `KMTQAITYPE_QUERY_ADAPTER_UNIQUE_GUID` reports the GUID value used by the adapter's registry key (DirectX and Video) @@ -278,6 +314,7 @@ ffGPUDetectWsl2 : adapterType.HybridDiscrete ? FF_GPU_TYPE_DISCRETE : FF_GPU_TYPE_UNKNOWN; + gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET; D3DKMT_DRIVERVERSION wddmVersion = KMT_DRIVERVERSION_WDDM_2_0; status = D3DKMTQueryAdapterInfo(&(D3DKMT_QUERYADAPTERINFO) { @@ -323,11 +360,7 @@ ffGPUDetectWsl2 .pPrivateDriverData = &deviceIds, .PrivateDriverDataSize = sizeof(deviceIds), }); - if (NT_SUCCESS(status) -#if FF_WIN81_COMPAT - || queryDeviceIdsFallback(adapterAddress, &deviceIds.DeviceIds) -#endif - ) { + if (NT_SUCCESS(status)) { ffStrbufSetStatic(&gpu->vendor, ffGPUGetVendorString(deviceIds.DeviceIds.VendorID)); FF_DEBUG("Adapter #%u vendor/device IDs: vendor=0x%04x device=0x%04x", i, @@ -338,6 +371,14 @@ ffGPUDetectWsl2 FF_DEBUG("KMTQAITYPE_PHYSICALADAPTERDEVICEIDS query failed for adapter #%u: %s", i, ffDebugNtStatus(status)); } + #if _WIN32 + if (adapterAddress.BusNumber != -1u) { + if (queryPciDeviceInfo(gpu, &deviceIds.DeviceIds) && gpu->vendor.length == 0) { + ffStrbufSetStatic(&gpu->vendor, ffGPUGetVendorString(deviceIds.DeviceIds.VendorID)); + } + } + #endif + D3DKMT_UMD_DRIVER_VERSION umdDriverVersion; status = D3DKMTQueryAdapterInfo(&(D3DKMT_QUERYADAPTERINFO) { .hAdapter = adapter->hAdapter, @@ -389,8 +430,10 @@ ffGPUDetectWsl2 .coreCount = options->driverSpecific ? (uint32_t*) &gpu->coreCount : NULL, .coreUsage = options->driverSpecific ? &gpu->coreUsage : NULL, .type = &gpu->type, - .name = &gpu->name, .frequency = options->driverSpecific ? &gpu->frequency : NULL, + .name = &gpu->name, + .psCurr = options->driverSpecific ? &gpu->psCurr : NULL, + .psMax = options->driverSpecific ? &gpu->psMax : NULL, }, dllName); FF_DEBUG("Driver-specific detection completed: %s", error ?: "Success"); @@ -553,25 +596,8 @@ ffGPUDetectWsl2 } if (gpu->type == FF_GPU_TYPE_UNKNOWN) { - FF_DEBUG("Using fallback GPU type detection"); - if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA) { - if (ffStrbufStartsWithIgnCaseS(&gpu->name, "GeForce") || - ffStrbufStartsWithIgnCaseS(&gpu->name, "Quadro") || - ffStrbufStartsWithIgnCaseS(&gpu->name, "Tesla")) { - gpu->type = FF_GPU_TYPE_DISCRETE; - } - } else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_MTHREADS) { - if (ffStrbufStartsWithIgnCaseS(&gpu->name, "MTT ")) { gpu->type = FF_GPU_TYPE_DISCRETE; } - } else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_INTEL) { - // 0000:00:02.0 is reserved for Intel integrated graphics - gpu->type = gpu->deviceId == ffGPUPciAddr2Id(0, 0, 2, 0) ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE; - } else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_VMWARE || gpu->vendor.chars == FF_GPU_VENDOR_NAME_PARALLELS) { - // Virtualized GPUs - gpu->type = FF_GPU_TYPE_INTEGRATED; - } - - if (gpu->type != FF_GPU_TYPE_UNKNOWN) { - FF_DEBUG("Determined GPU type based on vendor (%s) and name: %u", gpu->vendor.chars, gpu->type); + if (ffGPUFillVendorByDeviceName(gpu)) { + // OK } #if _WIN32 else if (ffIsWindows10OrGreater()) { diff --git a/src/detection/gpu/igcl.h b/src/detection/gpu/igcl.h index 6bf4ffe730..eb4e92e817 100644 --- a/src/detection/gpu/igcl.h +++ b/src/detection/gpu/igcl.h @@ -5,6 +5,7 @@ // DOCUMENTATION REFERENCED BELOW, IN ORDER TO MAKE FASTFETCH MIT COMPLIANT. #include +#include // https://intel.github.io/drivers.gpu.control-library/Control/api.html#_CPPv412ctl_result_t typedef enum ctl_result_t { @@ -73,7 +74,7 @@ typedef struct ctl_adapter_bdf_t { } ctl_adapter_bdf_t; #define IGCL_CTL_MAX_DEVICE_NAME_LEN 100 -#define IGCL_CTL_MAX_RESERVED_SIZE 112 +#define IGCL_CTL_MAX_RESERVED_SIZE 108 typedef enum ctl_adapter_properties_flag_t { CTL_ADAPTER_PROPERTIES_FLAG_INTEGRATED = 1, @@ -101,6 +102,7 @@ typedef struct ctl_device_adapter_properties_t { uint16_t pci_subsys_id; uint16_t pci_subsys_vendor_id; ctl_adapter_bdf_t adapter_bdf; + uint32_t num_xe_cores; char reserved[IGCL_CTL_MAX_RESERVED_SIZE]; } ctl_device_adapter_properties_t; @@ -214,3 +216,45 @@ typedef struct ctl_freq_properties_t { // https://intel.github.io/drivers.gpu.control-library/Control/api.html#_CPPv425ctlFrequencyGetProperties17ctl_freq_handle_tP21ctl_freq_properties_t extern ctl_result_t ctlFrequencyGetProperties(ctl_freq_handle_t hFrequency, ctl_freq_properties_t* pProperties); + +// https://intel.github.io/drivers.gpu.control-library/Control/api.html#_CPPv415ctl_pci_speed_t +typedef struct ctl_pci_speed_t { + uint32_t Size; + uint8_t Version; + int32_t gen; + int32_t width; + int64_t maxBandwidth; +} ctl_pci_speed_t; + +// https://intel.github.io/drivers.gpu.control-library/Control/api.html#_CPPv417ctl_pci_address_t +typedef struct ctl_pci_address_t { + uint32_t Size; + uint8_t Version; + uint32_t domain; + uint32_t bus; + uint32_t device; + uint32_t function; +} ctl_pci_address_t; + +// https://intel.github.io/drivers.gpu.control-library/Control/api.html#_CPPv420ctl_pci_properties_t +typedef struct ctl_pci_properties_t { + uint32_t Size; + uint8_t Version; + ctl_pci_address_t address; + ctl_pci_speed_t maxSpeed; + bool resizable_bar_supported; + bool resizable_bar_enabled; +} ctl_pci_properties_t; + +// https://intel.github.io/drivers.gpu.control-library/Control/api.html#ctlpcigetproperties +extern ctl_result_t ctlPciGetProperties(ctl_device_adapter_handle_t hDAhandle, ctl_pci_properties_t* pProperties); + +// https://intel.github.io/drivers.gpu.control-library/Control/api.html#ctl-pci-state-t +typedef struct _ctl_pci_state_t { + uint32_t Size; + uint8_t Version; + ctl_pci_speed_t speed; +} ctl_pci_state_t; + +// https://intel.github.io/drivers.gpu.control-library/Control/api.html#ctlpcigetstate +extern ctl_result_t ctlPciGetState(ctl_device_adapter_handle_t hDAhandle, ctl_pci_state_t* pState); diff --git a/src/detection/gpu/intel_drm.h b/src/detection/gpu/intel_drm.h index 3e25748225..a74fd3a0d1 100644 --- a/src/detection/gpu/intel_drm.h +++ b/src/detection/gpu/intel_drm.h @@ -1,7 +1,11 @@ #pragma once /* SPDX-License-Identifier: MIT */ -#include +#if __has_include() + #include +#else + #include +#endif // xe_drm.h diff --git a/src/detection/gpu/nvml.h b/src/detection/gpu/nvml.h index 74b1840500..52adaa3b5c 100644 --- a/src/detection/gpu/nvml.h +++ b/src/detection/gpu/nvml.h @@ -4,6 +4,8 @@ // THIS FILE IS CREATED FROM SCRATCH, BY READING THE OFFICIAL NVML API // DOCUMENTATION REFERENCED BELOW, IN ORDER TO MAKE FASTFETCH MIT COMPLIANT. +// https://docs.nvidia.com/deploy/pdf/NVML_API_Reference_Guide.pdf + // https://docs.nvidia.com/deploy/nvml-api/group__nvmlDeviceStructs.html #define NVML_DEVICE_PCI_BUS_ID_BUFFER_SIZE 32 #define NVML_DEVICE_PCI_BUS_ID_BUFFER_V2_SIZE 16 @@ -11,6 +13,7 @@ typedef enum { NVML_SUCCESS = 0 } nvmlReturn_t; typedef struct nvmlDevice_t* nvmlDevice_t; +#define NVML_STRUCT_VERSION(data, ver) (unsigned int)(sizeof(nvml##data##_v##ver##_t) | (ver << 24U)) // https://docs.nvidia.com/deploy/nvml-api/structnvmlPciInfo__t.html // PCI information about a GPU device @@ -54,7 +57,6 @@ typedef struct { unsigned long long used; } nvmlMemory_v2_t; // https://github.com/NVIDIA/nvidia-settings/issues/78#issuecomment-1012837988 -enum { nvmlMemory_v2 = (unsigned int) (sizeof(nvmlMemory_v2_t) | (2 << 24U)) }; // https://docs.nvidia.com/deploy/nvml-api/structnvmlMemory__t.html#structnvmlMemory__t // Memory allocation information for a device (v1) @@ -117,36 +119,73 @@ typedef struct unsigned int memory; } nvmlUtilization_t; +typedef struct { + // v1 + unsigned int version; + // input + nvmlTemperatureSensors_t sensorType; + // output + int temperature; +} nvmlTemperature_v1_t; + // https://docs.nvidia.com/deploy/nvml-api/group__nvmlInitializationAndCleanup.html#group__nvmlInitializationAndCleanup // Initialize NVML, but don't initialize any GPUs yet -nvmlReturn_t nvmlInit_v2(void); +extern nvmlReturn_t nvmlInit_v2(void); // Shut down NVML by releasing all GPU resources previously allocated with nvmlInit_v2() -nvmlReturn_t nvmlShutdown(void); +extern nvmlReturn_t nvmlShutdown(void); // https://docs.nvidia.com/deploy/nvml-api/group__nvmlDeviceQueries.html -// Retrieves the number of compute devices in the system. A compute device is a single GPU -extern nvmlReturn_t nvmlDeviceGetCount_v2(unsigned int* deviceCount); -// Acquire the handle for a particular device, based on its index -extern nvmlReturn_t nvmlDeviceGetHandleByIndex_v2(unsigned int index, nvmlDevice_t* device); -// Acquire the handle for a particular device, based on its PCI bus id -extern nvmlReturn_t nvmlDeviceGetHandleByPciBusId_v2(const char* pciBusId, nvmlDevice_t* device); + +// v545 // Retrieves the PCI attributes of this device extern nvmlReturn_t nvmlDeviceGetPciInfo_v3(nvmlDevice_t device, nvmlPciInfo_t* pci); -// Retrieves the current temperature readings for the device, in degrees C -extern nvmlReturn_t nvmlDeviceGetTemperature(nvmlDevice_t device, nvmlTemperatureSensors_t sensorType, unsigned int* temp); -// Retrieves the amount of used, free, reserved and total memory available on the device, in bytes. The reserved amount is supported on version 2 only -extern nvmlReturn_t nvmlDeviceGetMemoryInfo_v2(nvmlDevice_t device, nvmlMemory_v2_t* memory); -// Retrieves the amount of used, free, total memory available on the device, in bytes. -extern nvmlReturn_t nvmlDeviceGetMemoryInfo(nvmlDevice_t device, nvmlMemory_t* memory); + +// v510 // Gets the device's core count extern nvmlReturn_t nvmlDeviceGetNumGpuCores(nvmlDevice_t device, unsigned int* numCores); +// Retrieves the amount of used, free, reserved and total memory available on the device, in bytes. The reserved amount is supported on version 2 only +extern nvmlReturn_t nvmlDeviceGetMemoryInfo_v2(nvmlDevice_t device, nvmlMemory_v2_t* memory); + +// v361 // Retrieves the maximum clock speeds for the device extern nvmlReturn_t nvmlDeviceGetMaxClockInfo(nvmlDevice_t device, nvmlClockType_t type, unsigned int* clock); + +// v340 // Retrieves the brand of this device extern nvmlReturn_t nvmlDeviceGetBrand(nvmlDevice_t device, nvmlBrandType_t* type); -// Retrieves the current utilization rates for the device -extern nvmlReturn_t nvmlDeviceGetUtilizationRates(nvmlDevice_t device, nvmlUtilization_t* utilization); + +// v5.319 RC +// Retrieves the number of compute devices in the system. A compute device is a single GPU +extern nvmlReturn_t nvmlDeviceGetCount_v2(unsigned int* deviceCount); +// Acquire the handle for a particular device, based on its index +extern nvmlReturn_t nvmlDeviceGetHandleByIndex_v2(unsigned int index, nvmlDevice_t* device); // Retrieves the globally unique immutable UUID associated with this device, as a 5 part hexadecimal string, that augments the immutable, board serial identifier. extern nvmlReturn_t nvmlDeviceGetIndex(nvmlDevice_t device, unsigned int* index); + +// v3.295 +// Retrieves the maximum PCIe link generation possible with this device and system +extern nvmlReturn_t nvmlDeviceGetMaxPcieLinkGeneration(nvmlDevice_t device, unsigned int* maxLinkGen); +// Retrieves the maximum PCIe link width possible with this device and system +extern nvmlReturn_t nvmlDeviceGetMaxPcieLinkWidth(nvmlDevice_t device, unsigned int* maxLinkWidth); +// Retrieves the current PCIe link generation +extern nvmlReturn_t nvmlDeviceGetCurrPcieLinkGeneration(nvmlDevice_t device, unsigned int* currLinkGen); +// Retrieves the current PCIe link width +extern nvmlReturn_t nvmlDeviceGetCurrPcieLinkWidth(nvmlDevice_t device, unsigned int* currLinkWidth); + +// v0 +// Acquire the handle for a particular device, based on its PCI bus id +extern nvmlReturn_t nvmlDeviceGetHandleByPciBusId_v2(const char* pciBusId, nvmlDevice_t* device); +// Retrieves the amount of used, free, total memory available on the device, in bytes. +extern nvmlReturn_t nvmlDeviceGetMemoryInfo(nvmlDevice_t device, nvmlMemory_t* memory); +// Retrieves the current utilization rates for the device +extern nvmlReturn_t nvmlDeviceGetUtilizationRates(nvmlDevice_t device, nvmlUtilization_t* utilization); // Retrieves the name of this device. extern nvmlReturn_t nvmlDeviceGetName(nvmlDevice_t device, char* name, unsigned int length); +// Retrieves the current temperature readings (in degrees C) for the given device +extern nvmlReturn_t nvmlDeviceGetTemperatureV(nvmlDevice_t device, nvmlTemperature_v1_t* temperature); + + +enum { + nvmlMemory_v2 = NVML_STRUCT_VERSION(Memory, 2), + nvmlTemperature_v1 = NVML_STRUCT_VERSION(Temperature, 1), +}; diff --git a/src/detection/libc/libc_android.c b/src/detection/libc/libc_android.c index 2aec4ed207..9d7762c783 100644 --- a/src/detection/libc/libc_android.c +++ b/src/detection/libc/libc_android.c @@ -1,7 +1,5 @@ #include "libc.h" - -#define FF_STR_INDIR(x) #x -#define FF_STR(x) FF_STR_INDIR(x) +#include "common/strutil.h" #include diff --git a/src/detection/libc/libc_linux.c b/src/detection/libc/libc_linux.c index 53186a3568..a445c7b9b5 100644 --- a/src/detection/libc/libc_linux.c +++ b/src/detection/libc/libc_linux.c @@ -1,7 +1,5 @@ #include "libc.h" - -#define FF_STR_INDIR(x) #x -#define FF_STR(x) FF_STR_INDIR(x) +#include "common/strutil.h" #include diff --git a/src/detection/opencl/opencl.c b/src/detection/opencl/opencl.c index 14216ac090..74f8f6144d 100644 --- a/src/detection/opencl/opencl.c +++ b/src/detection/opencl/opencl.c @@ -101,6 +101,7 @@ static const char* openCLHandleData(OpenCLData* data, FFOpenCLResult* result) { gpu->deviceId = (size_t) deviceID; gpu->frequency = FF_GPU_FREQUENCY_UNSET; gpu->coreUsage = FF_GPU_CORE_USAGE_UNSET; + gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET; if (data->ffclGetDeviceInfo(deviceID, CL_DEVICE_VERSION, sizeof(buffer), buffer, NULL) == CL_SUCCESS) { ffStrbufSetS(&gpu->platformApi, buffer); diff --git a/src/detection/opengl/opengl_shared.c b/src/detection/opengl/opengl_shared.c index 307e71d1ba..c483879cbe 100644 --- a/src/detection/opengl/opengl_shared.c +++ b/src/detection/opengl/opengl_shared.c @@ -1,6 +1,7 @@ #include "opengl.h" #include "common/debug.h" #include "common/library.h" +#include "common/io.h" #if __has_include() #include @@ -34,8 +35,6 @@ void ffOpenGLHandleResult(FFOpenGLResult* result, __typeof__(&glGetString) ffglG typedef struct EGLData { FF_LIBRARY_SYMBOL(glGetString) - FF_LIBRARY_SYMBOL(eglGetProcAddress) - FF_LIBRARY_SYMBOL(eglGetDisplay) FF_LIBRARY_SYMBOL(eglQueryString) FF_LIBRARY_SYMBOL(eglInitialize) FF_LIBRARY_SYMBOL(eglBindAPI) @@ -132,38 +131,7 @@ static const char* eglHandleDisplay(FFOpenGLResult* result, EGLData* data) { return error; } -static const char* eglHandleData(FFOpenGLResult* result, EGLData* data) { - FF_DEBUG("Resolving glGetString via eglGetProcAddress()"); - data->ffglGetString = (__typeof__(&glGetString)) data->ffeglGetProcAddress("glGetString"); - if (!data->ffglGetString) { - FF_DEBUG("eglGetProcAddress('glGetString') returned NULL"); - return "eglGetProcAddress(glGetString) returned NULL"; - } - - #if EGL_VERSION_1_5 - PFNEGLGETPLATFORMDISPLAYEXTPROC ffeglGetPlatformDisplay = (PFNEGLGETPLATFORMDISPLAYEXTPROC) data->ffeglGetProcAddress("eglGetPlatformDisplay"); - if (ffeglGetPlatformDisplay) { - FF_DEBUG("Trying eglGetPlatformDisplay(EGL_PLATFORM_SURFACELESS_MESA)"); - data->display = ffeglGetPlatformDisplay(EGL_PLATFORM_SURFACELESS_MESA, NULL, NULL); - FF_DEBUG("eglGetPlatformDisplay() %s", data->display == EGL_NO_DISPLAY ? "failed" : "succeeded"); - } else { - FF_DEBUG("eglGetPlatformDisplay is unavailable, falling back to eglGetDisplay"); - } - - if (!ffeglGetPlatformDisplay || data->display == EGL_NO_DISPLAY) - #endif - - { - FF_DEBUG("Trying eglGetDisplay(EGL_DEFAULT_DISPLAY)"); - data->display = data->ffeglGetDisplay(EGL_DEFAULT_DISPLAY); - if (data->display == EGL_NO_DISPLAY) { - FF_DEBUG("eglGetDisplay() returned EGL_NO_DISPLAY"); - return "eglGetDisplay returned EGL_NO_DISPLAY"; - } - - FF_DEBUG("eglGetDisplay() succeeded"); - } - +static const char* eglHandlePreDisplay(FFOpenGLResult* result, EGLData* data) { EGLint major, minor; if (data->ffeglInitialize(data->display, &major, &minor) == EGL_FALSE) { FF_DEBUG("eglInitialize() returned EGL_FALSE"); @@ -185,8 +153,7 @@ const char* ffOpenGLDetectByEGL(FFOpenGLResult* result) { EGLData eglData; FF_LIBRARY_LOAD_MESSAGE(egl, "libEGL" FF_LIBRARY_EXTENSION, 1); - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(egl, eglData, eglGetProcAddress); - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(egl, eglData, eglGetDisplay); + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(egl, eglGetProcAddress); FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(egl, eglData, eglQueryString); FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(egl, eglData, eglInitialize); FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(egl, eglData, eglBindAPI); @@ -198,12 +165,50 @@ const char* ffOpenGLDetectByEGL(FFOpenGLResult* result) { FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(egl, eglData, eglDestroySurface); FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(egl, eglData, eglTerminate); + FF_DEBUG("Resolving glGetString via eglGetProcAddress()"); + eglData.ffglGetString = (__typeof__(&glGetString)) ffeglGetProcAddress("glGetString"); + if (!eglData.ffglGetString) { + FF_DEBUG("eglGetProcAddress('glGetString') returned NULL"); + return "eglGetProcAddress(glGetString) returned NULL"; + } + FF_DEBUG("Loaded EGL library and required symbols"); FF_SUPPRESS_IO(); - FF_DEBUG("Suppressed stdout/stderr during EGL probing"); - const char* error = eglHandleData(result, &eglData); + EGLDisplay display = EGL_NO_DISPLAY; + #if EGL_VERSION_1_5 + PFNEGLGETPLATFORMDISPLAYEXTPROC ffeglGetPlatformDisplay = (PFNEGLGETPLATFORMDISPLAYEXTPROC) ffeglGetProcAddress("eglGetPlatformDisplay"); + if (!ffeglGetPlatformDisplay) { + ffeglGetPlatformDisplay = (PFNEGLGETPLATFORMDISPLAYEXTPROC) ffeglGetProcAddress("eglGetPlatformDisplayEXT"); + } + if (ffeglGetPlatformDisplay) { + FF_DEBUG("Trying eglGetPlatformDisplay(EGL_PLATFORM_SURFACELESS_MESA)"); + display = ffeglGetPlatformDisplay(EGL_PLATFORM_SURFACELESS_MESA, EGL_DEFAULT_DISPLAY, NULL); + FF_DEBUG("eglGetPlatformDisplay() %s", display == EGL_NO_DISPLAY ? "failed" : "succeeded"); + } else { + FF_DEBUG("eglGetPlatformDisplay is unavailable, falling back to eglGetDisplay"); + } + + if (display == EGL_NO_DISPLAY) + #endif + + { + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(egl, eglGetDisplay); + + FF_DEBUG("Trying eglGetDisplay(EGL_DEFAULT_DISPLAY)"); + display = ffeglGetDisplay(EGL_DEFAULT_DISPLAY); + if (display == EGL_NO_DISPLAY) { + FF_DEBUG("eglGetDisplay() returned EGL_NO_DISPLAY"); + return "eglGetDisplay returned EGL_NO_DISPLAY"; + } + + FF_DEBUG("eglGetDisplay() succeeded"); + } + eglData.display = display; + + const char* error = eglHandlePreDisplay(result, &eglData); + FF_DEBUG("OpenGL detection via EGL returns: %s", error ?: "success"); return error; diff --git a/src/detection/os/os_apple.m b/src/detection/os/os_apple.m index 2890fc31ab..570a723234 100644 --- a/src/detection/os/os_apple.m +++ b/src/detection/os/os_apple.m @@ -44,6 +44,7 @@ static bool detectOSCodeName(FFOSResult* os) switch (num) { + case 27: ffStrbufSetStatic(&os->codename, "Golden Gate"); return true; case 26: case 16: ffStrbufSetStatic(&os->codename, "Tahoe"); return true; case 15: ffStrbufSetStatic(&os->codename, "Sequoia"); return true; diff --git a/src/detection/os/os_linux.c b/src/detection/os/os_linux.c index fc653a3c64..d3eeb43268 100644 --- a/src/detection/os/os_linux.c +++ b/src/detection/os/os_linux.c @@ -8,9 +8,6 @@ #include #include -#define FF_STR_INDIR(x) #x -#define FF_STR(x) FF_STR_INDIR(x) - static bool parseLsbRelease(const char* fileName, FFOSResult* result) { return ffParsePropFileValues(fileName, 4, (FFpropquery[]) { { "DISTRIB_ID =", &result->id }, diff --git a/src/detection/packages/packages.h b/src/detection/packages/packages.h index f0d42004de..2119349323 100644 --- a/src/detection/packages/packages.h +++ b/src/detection/packages/packages.h @@ -22,6 +22,7 @@ typedef struct FFPackagesResult { uint32_t guixUser; uint32_t hpkgSystem; uint32_t hpkgUser; + uint32_t installrelease; uint32_t kiss; uint32_t linglong; uint32_t lpkg; @@ -40,6 +41,7 @@ typedef struct FFPackagesResult { uint32_t pkg; uint32_t pkgsrc; uint32_t pkgtool; + uint32_t porg; uint32_t rpm; uint32_t scoopGlobal; uint32_t scoopUser; diff --git a/src/detection/packages/packages_linux.c b/src/detection/packages/packages_linux.c index 79de8cb3e3..ee4efbe4ce 100644 --- a/src/detection/packages/packages_linux.c +++ b/src/detection/packages/packages_linux.c @@ -84,7 +84,7 @@ static uint32_t countFilesRecursiveImpl(FFstrbuf* baseDirPath, const char* filen return 1; } - DIR* dirp = opendir(baseDirPath->chars); + FF_AUTO_CLOSE_DIR DIR* dirp = opendir(baseDirPath->chars); if (dirp == NULL) { return 0; } @@ -106,7 +106,6 @@ static uint32_t countFilesRecursiveImpl(FFstrbuf* baseDirPath, const char* filen ffStrbufSubstrBefore(baseDirPath, baseDirPathLength); } - closedir(dirp); return sum; } @@ -138,7 +137,7 @@ static uint32_t getNumElementsBySuffix(FFstrbuf* baseDir, const char* dirname, c } static uint32_t getXBPSImpl(FFstrbuf* baseDir) { - DIR* dir = opendir(baseDir->chars); + FF_AUTO_CLOSE_DIR DIR* dir = opendir(baseDir->chars); if (dir == NULL) { return 0; } @@ -157,7 +156,6 @@ static uint32_t getXBPSImpl(FFstrbuf* baseDir) { break; } - closedir(dir); return result; } @@ -458,6 +456,33 @@ static uint32_t getPacmanPackages(FFstrbuf* baseDir) { return getNumElements(baseDir, dbPath.chars, true); } +static uint32_t getEmergePackagesImpl(FFstrbuf* baseDir) { + FF_AUTO_CLOSE_DIR DIR* dirp = opendir(baseDir->chars); + if (dirp == NULL) + return 0; + + uint32_t result = 0; + + struct dirent *entry; + while ((entry = readdir(dirp)) != NULL) + { + if (entry->d_type != DT_DIR || entry->d_name[0] == '.') + continue; + + result += getNumElements(baseDir, entry->d_name, true); + } + return result; +} + +static uint32_t getEmergePackages(FFstrbuf* baseDir, const char* dirname) { + uint32_t baseDirLength = baseDir->length; + ffStrbufAppendS(baseDir, dirname); + ffStrbufAppendC(baseDir, '/'); + uint32_t result = getEmergePackagesImpl(baseDir); + ffStrbufSubstrBefore(baseDir, baseDirLength); + return result; +} + static void getPackageCounts(FFstrbuf* baseDir, FFPackagesResult* packageCounts, FFPackagesOptions* options) { if (FF_PACKAGES_IS_ENABLED(options, APK)) { packageCounts->apk += getNumStrings(baseDir, "/lib/apk/db/installed", "C:Q", "apk"); @@ -469,7 +494,7 @@ static void getPackageCounts(FFstrbuf* baseDir, FFPackagesResult* packageCounts, packageCounts->lpkg += getNumStrings(baseDir, "/opt/Loc-OS-LPKG/installed-lpkg/Listinstalled-lpkg.list", "\n", "lpkg"); } if (FF_PACKAGES_IS_ENABLED(options, EMERGE)) { - packageCounts->emerge += countFilesRecursive(baseDir, "/var/db/pkg", "SIZE"); + packageCounts->emerge += getEmergePackages(baseDir, "/var/db/pkg"); } if (FF_PACKAGES_IS_ENABLED(options, EOPKG)) { packageCounts->eopkg += getNumElements(baseDir, "/var/lib/eopkg/package", true); @@ -493,6 +518,9 @@ static void getPackageCounts(FFstrbuf* baseDir, FFPackagesResult* packageCounts, if (FF_PACKAGES_IS_ENABLED(options, PKGTOOL)) { packageCounts->pkgtool += getNumElements(baseDir, "/var/log/packages", false); } + if (FF_PACKAGES_IS_ENABLED(options, PORG)) { + packageCounts->porg += getNumElements(baseDir, "/var/log/porg", false); + } if (FF_PACKAGES_IS_ENABLED(options, RPM)) { // `Sigmd5` is the only table that doesn't contain the virtual `gpg-pubkey` package packageCounts->rpm += getSQLite3Int(baseDir, "/var/lib/rpm/rpmdb.sqlite", "SELECT count(*) FROM Sigmd5", "rpm"); @@ -586,6 +614,25 @@ static void getPackageCountsBedrock(FFstrbuf* baseDir, FFPackagesResult* package ffStrbufSubstrBefore(baseDir, baseDirLength); } +static uint32_t getInstallReleasePackages(FFstrbuf* baseDir) { + uint32_t result = 0; + + uint32_t baseDirLength = baseDir->length; + ffStrbufAppendS(baseDir, ".config/install_release/state.json"); + if (ffPathExists(baseDir->chars, FF_PATHTYPE_ANY)) { + yyjson_doc* doc = yyjson_read_file(baseDir->chars, YYJSON_READ_NOFLAG, NULL, NULL); + if (doc != NULL) { + yyjson_val* root = yyjson_doc_get_root(doc); + if (yyjson_is_obj(root)) { + result = (uint32_t) yyjson_obj_size(root); + } + yyjson_doc_free(doc); + } + } + ffStrbufSubstrBefore(baseDir, baseDirLength); + return result; +} + void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options) { FF_STRBUF_AUTO_DESTROY baseDir = ffStrbufCreateA(512); ffStrbufAppendS(&baseDir, FASTFETCH_TARGET_DIR_ROOT); @@ -648,4 +695,8 @@ void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options) result->appimage += getNumElementsBySuffix(&baseDir, "/AppImages", ".appimage"); result->appimage += getNumElementsBySuffix(&baseDir, "/Applications", ".appimage"); } + + if (FF_PACKAGES_IS_ENABLED(options, INSTALLRELEASE)) { + result->installrelease = getInstallReleasePackages(&baseDir); + } } diff --git a/src/detection/terminalfont/terminalfont_linux.c b/src/detection/terminalfont/terminalfont_linux.c index bfc8959dce..9ae16a4301 100644 --- a/src/detection/terminalfont/terminalfont_linux.c +++ b/src/detection/terminalfont/terminalfont_linux.c @@ -401,6 +401,24 @@ static void detectWestonTerminal(FFTerminalFontResult* terminalFont) { ffFontInitValues(&terminalFont->font, font.chars, size.chars); } +static void detectKmscon(FFTerminalFontResult* terminalFont) { + FF_STRBUF_AUTO_DESTROY fontName = ffStrbufCreate(); + FF_STRBUF_AUTO_DESTROY fontSize = ffStrbufCreate(); + + ffParsePropFileConfigValues("kmscon/kmscon.conf", 2, (FFpropquery[]){ + { "font-size=", &fontSize }, + { "font-name=", &fontName }, + }); + + if (fontName.length == 0) { + ffStrbufSetStatic(&fontName, "Hack Nerd Font"); + } + if (fontSize.length == 0) { + ffStrbufSetStatic(&fontSize, "18"); + } + ffFontInitValues(&terminalFont->font, fontName.chars, fontSize.chars); +} + static void detectUrxvt(FFTerminalFontResult* terminalFont) { FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate(); @@ -522,6 +540,8 @@ ffDetectTerminalFontPlatform detectWarp(terminalFont); } else if (ffStrbufIgnCaseEqualS(&terminal->processName, "weston-terminal")) { detectWestonTerminal(terminalFont); + } else if (ffStrbufIgnCaseEqualS(&terminal->processName, "kmscon")) { + detectKmscon(terminalFont); } else if (ffStrbufStartsWithIgnCaseS(&terminal->processName, "terminator")) { detectTerminator(terminalFont); } else if (ffStrbufStartsWithIgnCaseS(&terminal->processName, "sakura")) { diff --git a/src/detection/terminalshell/terminalshell.c b/src/detection/terminalshell/terminalshell.c index 222221660b..b3c7d67108 100644 --- a/src/detection/terminalshell/terminalshell.c +++ b/src/detection/terminalshell/terminalshell.c @@ -503,6 +503,36 @@ FF_A_UNUSED static bool getTerminalVersionWeston(FF_A_UNUSED FFstrbuf* exe, FFst return version->length > 0; } +FF_A_UNUSED static bool extractKmsconVersion(const char* str, FF_A_UNUSED uint32_t len, void* userdata) { + if (!ffStrStartsWith(str, "v")) { + return true; + } + int count = 0; + sscanf(str, "v%*d.%*d.%*d%n", &count); + if (count == 0) { + return true; + } + ffStrbufSetNS((FFstrbuf*) userdata, (uint32_t) count - 1, str + 1); + return false; +} + +FF_A_UNUSED static bool getTerminalVersionKmscon(FFstrbuf* exe, FFstrbuf* version) { + if (ffIsAbsolutePath(exe->chars)) { + ffBinaryExtractStrings(exe->chars, extractKmsconVersion, version, (uint32_t) strlen("v0.0.0")); + if (version->length) { + return true; + } + } + + if (!getExeVersionRaw(exe, version)) { + return false; + } + + // kmscon version v10.0.0 + ffStrbufSubstrAfterLastC(version, ' '); + return version->length > 0; +} + static bool getTerminalVersionContour(FFstrbuf* exe, FFstrbuf* version) { const char* env = getenv("TERMINAL_VERSION_STRING"); if (env) { @@ -840,6 +870,14 @@ bool fftsGetTerminalVersion(FFstrbuf* processName, FF_A_UNUSED FFstrbuf* exe, FF #endif +#ifdef __linux__ + + if (ffStrbufIgnCaseEqualS(processName, "kmscon")) { + return getTerminalVersionKmscon(exe, version); + } + +#endif + #ifdef _WIN32 if (ffStrbufIgnCaseEqualS(processName, "WindowsTerminal.exe")) { diff --git a/src/detection/version/version.c b/src/detection/version/version.c index 8bd066ec06..b3c35141c2 100644 --- a/src/detection/version/version.c +++ b/src/detection/version/version.c @@ -1,4 +1,5 @@ #include "version.h" +#include "common/strutil.h" #if defined(__x86_64__) #define FF_ARCHITECTURE "x86_64" @@ -62,9 +63,6 @@ #define FF_SYSNAME "Unknown" #endif -#define FF_STR_INDIR(x) #x -#define FF_STR(x) FF_STR_INDIR(x) - FFVersionResult ffVersionResult = { .projectName = FASTFETCH_PROJECT_NAME, .sysName = FF_SYSNAME, diff --git a/src/detection/vulkan/vulkan.c b/src/detection/vulkan/vulkan.c index 013c457266..a6b6fefc0f 100644 --- a/src/detection/vulkan/vulkan.c +++ b/src/detection/vulkan/vulkan.c @@ -280,6 +280,7 @@ static const char* detectVulkan(FFVulkanResult* result) { gpu->temperature = FF_GPU_TEMP_UNSET; gpu->frequency = FF_GPU_FREQUENCY_UNSET; gpu->coreUsage = FF_GPU_CORE_USAGE_UNSET; + gpu->pcieSpeed = FF_GPU_PCIE_SPEED_UNSET; next: continue; diff --git a/src/detection/wifi/wifi_bsd.c b/src/detection/wifi/wifi_bsd.c index fab1293bca..4b49b4e56b 100644 --- a/src/detection/wifi/wifi_bsd.c +++ b/src/detection/wifi/wifi_bsd.c @@ -133,14 +133,24 @@ const char* ffDetectWifi(FFlist* result) { ffStrbufSetStatic(&item->conn.security, "Shared"); break; case IEEE80211_AUTH_8021X: - ffStrbufSetStatic(&item->conn.security, "8021X"); + ffStrbufSetStatic(&item->conn.security, "802.1x"); break; case IEEE80211_AUTH_AUTO: ffStrbufSetStatic(&item->conn.security, "Auto"); break; - case IEEE80211_AUTH_WPA: - ffStrbufSetStatic(&item->conn.security, "WPA"); + case IEEE80211_AUTH_WPA: { + ireq.i_type = IEEE80211_IOC_WPA; + if (ioctl(sock, SIOCG80211, &ireq) >= 0) { + switch (ireq.i_val) { + case 2: ffStrbufSetStatic(&item->conn.security, "WPA2"); break; + case 3: ffStrbufSetStatic(&item->conn.security, "WPA1+2"); break; + default: ffStrbufSetStatic(&item->conn.security, "WPA"); break; + } + } else { + ffStrbufSetStatic(&item->conn.security, "WPA"); + } break; + } default: ffStrbufSetF(&item->conn.security, "Unknown (%d)", ireq.i_val); break; diff --git a/src/detection/wm/wm_linux.c b/src/detection/wm/wm_linux.c index a62a4af9ac..35dbeb12e8 100644 --- a/src/detection/wm/wm_linux.c +++ b/src/detection/wm/wm_linux.c @@ -169,6 +169,22 @@ static const char* getNiri(FFstrbuf* result) { return "Failed to run command `niri --version`"; } +static const char* getWeston(FFstrbuf* result) { + FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate(); + const char* error = ffFindExecutableInPath("weston", &path); + if (error) { + return "Failed to find weston executable path"; + } + + if (ffProcessAppendStdOut(result, (char* const[]) { path.chars, "--version", NULL }) == NULL) { // weston 8.0.0\n... + ffStrbufSubstrBeforeFirstC(result, '\n'); + ffStrbufSubstrAfterLastC(result, ' '); + return NULL; + } + + return "Failed to run command `weston --version`"; +} + #ifdef __linux__ static const char* getWslg(FFstrbuf* result) { if (!ffAppendFileBuffer("/mnt/wslg/versions.txt", result)) { @@ -307,6 +323,10 @@ const char* ffDetectWMVersion(const FFstrbuf* wmName, FFstrbuf* result, FF_A_UNU return getNiri(result); } + if (ffStrbufEqualS(wmName, "weston")) { + return getWeston(result); + } + #if __linux__ if (ffStrbufEqualS(wmName, "WSLg")) { return getWslg(result); diff --git a/src/fastfetch.c b/src/fastfetch.c index dc5c1797d8..e644409251 100644 --- a/src/fastfetch.c +++ b/src/fastfetch.c @@ -15,6 +15,7 @@ #include #include +FF_A_COLD static void printCommandFormatHelpJson(void) { yyjson_mut_doc* doc = yyjson_mut_doc_new(NULL); yyjson_mut_val* root = yyjson_mut_obj(doc); @@ -49,6 +50,7 @@ static void printCommandFormatHelpJson(void) { yyjson_mut_doc_free(doc); } +FF_A_COLD static void printCommandFormatHelp(const char* command) { FF_STRBUF_AUTO_DESTROY type = ffStrbufCreateNS((uint32_t) (strlen(command) - strlen("-format")), command); ffStrbufLowerCase(&type); @@ -85,6 +87,7 @@ static void printCommandFormatHelp(const char* command) { fprintf(stderr, "Error: Module '%s' is not supported\n", type.chars); } +FF_A_COLD static void printFullHelp() { fputs("Fastfetch is a neofetch-like tool for fetching system information and displaying them in a pretty way\n\n", stdout); if (!instance.config.display.pipe) { @@ -191,6 +194,7 @@ For detailed information on logo options, module configuration, and formatting, https://github.com/fastfetch-cli/fastfetch/wiki/Configuration"); } +FF_A_COLD static bool printSpecificCommandHelp(const char* command) { yyjson_doc* doc = yyjson_read(FASTFETCH_DATATEXT_JSON_HELP, strlen(FASTFETCH_DATATEXT_JSON_HELP), YYJSON_READ_NOFLAG); assert(doc); @@ -301,6 +305,7 @@ static bool printSpecificCommandHelp(const char* command) { return false; } +FF_A_COLD static void printCommandHelp(const char* command) { if (command == NULL) { printFullHelp(); @@ -313,6 +318,7 @@ static void printCommandHelp(const char* command) { } } +FF_A_COLD static void listAvailablePresets(bool pretty) { FF_LIST_FOR_EACH (FFstrbuf, path, instance.state.platform.dataDirs) { ffStrbufAppendS(path, "fastfetch/presets/"); @@ -327,6 +333,7 @@ static void listAvailablePresets(bool pretty) { } } +FF_A_COLD static void listAvailableLogos(void) { FF_LIST_FOR_EACH (FFstrbuf, path, instance.state.platform.dataDirs) { ffStrbufAppendS(path, "fastfetch/logos/"); @@ -334,6 +341,7 @@ static void listAvailableLogos(void) { } } +FF_A_COLD static void listConfigPaths(void) { FF_LIST_FOR_EACH (FFstrbuf, folder, instance.state.platform.configDirs) { bool exists = false; @@ -345,6 +353,7 @@ static void listConfigPaths(void) { } } +FF_A_COLD static void listDataPaths(void) { FF_LIST_FOR_EACH (FFstrbuf, folder, instance.state.platform.dataDirs) { ffStrbufAppendS(folder, "fastfetch/"); @@ -352,6 +361,7 @@ static void listDataPaths(void) { } } +FF_A_COLD static void listModules(bool pretty) { unsigned count = 0; for (int i = 0; i <= 'Z' - 'A'; ++i) { @@ -394,20 +404,26 @@ static bool parseJsoncFile(FFdata* data, const char* path, yyjson_read_flag flg) } { - const char* error = NULL; - yyjson_val* const root = yyjson_doc_get_root(data->configDoc); if (!yyjson_is_obj(root)) { - error = "Invalid JSON config format. Root value must be an object"; + fputs("JsonConfig Error: Invalid JSON config format. Root value must be an object", stderr); + exit(477); } + yyjson_val* problematicKey = NULL; + const char* error = NULL; + const char* problematicModule = NULL; if ( error || - (error = ffOptionsParseLogoJsonConfig(&instance.config.logo, root)) || - (error = ffOptionsParseGeneralJsonConfig(&instance.config.general, root)) || - (error = ffOptionsParseDisplayJsonConfig(&instance.config.display, root)) || + ((error = ffOptionsParseLogoJsonConfig(&instance.config.logo, root, &problematicKey)) && (problematicModule = "logo")) || + ((error = ffOptionsParseGeneralJsonConfig(&instance.config.general, root, &problematicKey)) && (problematicModule = "general")) || + ((error = ffOptionsParseDisplayJsonConfig(&instance.config.display, root, &problematicKey)) && (problematicModule = "display")) || false) { - fprintf(stderr, "JsonConfig Error: %s\n", error); + if (problematicKey) { + fprintf(stderr, "JsonConfig Error (%s.%s): %s\n", problematicModule, unsafe_yyjson_get_str(problematicKey), error); + } else { + fprintf(stderr, "JsonConfig Error (%s): %s\n", problematicModule, error); + } exit(477); } } @@ -415,6 +431,7 @@ static bool parseJsoncFile(FFdata* data, const char* path, yyjson_read_flag flg) return true; } +FF_A_COLD static void generateConfigFile(FFdata* data, bool force, const char* filePath, bool fullConfig) { if (data->resultDoc) { fprintf(stderr, "Error: duplicated `--gen-config` or `--format json` flags found\n"); @@ -552,6 +569,7 @@ static void optionParseConfigFile(FFdata* data, const char* key, const char* val exit(414); } +FF_A_COLD static void printVersion() { FFVersionResult* result = &ffVersionResult; printf("%s %s%s%s (%s)\n", result->projectName, result->version, result->versionTweak, result->debugMode ? "-debug" : "", result->architecture); @@ -572,8 +590,7 @@ static void parseCommand(FFdata* data, char* key, char* value) { if (ffStrEqualsIgnCase(key, "-h") || ffStrEqualsIgnCase(key, "--help")) { printCommandHelp(value); exit(0); - } - if (ffStrEqualsIgnCase(key, "--help-raw")) { + } else if (ffStrEqualsIgnCase(key, "--help-raw")) { puts(FASTFETCH_DATATEXT_JSON_HELP); exit(0); } else if (ffStrEqualsIgnCase(key, "-v") || ffStrEqualsIgnCase(key, "--version")) { @@ -792,6 +809,7 @@ static void run(FFdata* data) { } } +FF_A_COLD static void writeConfigFile(FFdata* data) { const FFstrbuf* filename = &data->genConfigPath; diff --git a/src/logo/ascii/z.inc b/src/logo/ascii/z.inc index 393c906313..d2371f9a73 100644 --- a/src/logo/ascii/z.inc +++ b/src/logo/ascii/z.inc @@ -3,6 +3,18 @@ #include "common/color.h" static const FFlogo Z[] = { + #ifdef FASTFETCH_DATATEXT_LOGO_ZERENE + // Zerene + { + .names = { "Zerene" }, + .lines = FASTFETCH_DATATEXT_LOGO_ZERENE, + .colors = { + FF_COLOR_FG_BLUE, + }, + .colorKeys = FF_COLOR_FG_BLUE, + .colorTitle = FF_COLOR_FG_BLUE, + }, + #endif #ifdef FASTFETCH_DATATEXT_LOGO_ZORIN // Zorin { diff --git a/src/logo/ascii/z/zerene.txt b/src/logo/ascii/z/zerene.txt new file mode 100644 index 0000000000..3d0e0ce9bd --- /dev/null +++ b/src/logo/ascii/z/zerene.txt @@ -0,0 +1,18 @@ + MMM + MMMM + MMMMM + MMMMMM + MMMMMMa + MMMMMMMa + MMMMMMM + MMMMMM + MMMM + M + oxdo aMa + aMd aMMMMMMMMM + aMMMMM MMMMMMMMMMMMMMa + MMMMMMMa MMMMMMMMMMMMMMMa + MMMMMMMMa + MMMMMMMMa + MMMMMMM +MMMM diff --git a/src/logo/image/image.c b/src/logo/image/image.c index 78083e68e8..6dd3212151 100644 --- a/src/logo/image/image.c +++ b/src/logo/image/image.c @@ -727,7 +727,7 @@ FFLogoImageResult ffLogoPrintImageImpl(FFLogoRequestData* requestData, const FFI bool printSuccessful = false; if (requestData->type == FF_LOGO_TYPE_IMAGE_CHAFA) { - #ifdef FF_HAVE_CHAFA + #if FF_HAVE_CHAFA printSuccessful = printImageChafa(requestData, &imageData); #endif } else if (requestData->type == FF_LOGO_TYPE_IMAGE_KITTY) { @@ -782,12 +782,9 @@ static uint32_t readCachedUint32(FFLogoRequestData* requestData, const char* cac return result; } -static bool printCachedChars(FFLogoRequestData* requestData) { - FF_STRBUF_AUTO_DESTROY content = ffStrbufCreateA(32768); - - if (requestData->type == FF_LOGO_TYPE_IMAGE_CHAFA) { - readCachedStrbuf(requestData, &content, FF_CACHE_FILE_CHAFA); - } +static bool printCachedChars(FFLogoRequestData* requestData, const char* cacheFileName) { + FF_STRBUF_AUTO_DESTROY content = ffStrbufCreate(); + readCachedStrbuf(requestData, &content, cacheFileName); if (content.length == 0) { return false; @@ -876,14 +873,6 @@ static bool printCachedPixel(FFLogoRequestData* requestData) { return true; } -static bool printCached(FFLogoRequestData* requestData) { - if (requestData->type == FF_LOGO_TYPE_IMAGE_CHAFA) { - return printCachedChars(requestData); - } else { - return printCachedPixel(requestData); - } -} - static bool getCharacterPixelDimensions(FFLogoRequestData* requestData) { #ifdef _WIN32 @@ -947,9 +936,14 @@ static bool printImageIfExistsSlowPath(FFLogoType type, bool printError) { ffStrbufEnsureEndsWithC(&requestData.cacheDir, '/'); ffStrbufAppendF(&requestData.cacheDir, "%u*%u/", requestData.logoPixelWidth, requestData.logoPixelHeight); - if (!instance.config.logo.recache && printCached(&requestData)) { - ffStrbufDestroy(&requestData.cacheDir); - return true; + if (!instance.config.logo.recache) { + bool cacheValid = requestData.type == FF_LOGO_TYPE_IMAGE_CHAFA + ? printCachedChars(&requestData, FF_CACHE_FILE_CHAFA) + : printCachedPixel(&requestData); + if (cacheValid) { + ffStrbufDestroy(&requestData.cacheDir); + return true; + } } FFLogoImageResult result = FF_LOGO_IMAGE_RESULT_INIT_ERROR; @@ -1018,7 +1012,7 @@ bool ffLogoPrintImageIfExists(FFLogoType type, bool printError) { return printImageKittyIcat(printError); } -#if !defined(FF_HAVE_CHAFA) +#if !FF_HAVE_CHAFA if (type == FF_LOGO_TYPE_IMAGE_CHAFA) { if (printError) { fputs("Logo: Chafa support is not compiled in\n", stderr); diff --git a/src/modules/bluetooth/bluetooth.c b/src/modules/bluetooth/bluetooth.c index 641acebdc6..6721c336da 100644 --- a/src/modules/bluetooth/bluetooth.c +++ b/src/modules/bluetooth/bluetooth.c @@ -66,6 +66,7 @@ bool ffPrintBluetooth(FFBluetoothOptions* options) { if (devices.length == 0) { ffPrintError(FF_BLUETOOTH_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "No bluetooth devices found"); + return false; } uint8_t i = 1; diff --git a/src/modules/bluetoothradio/bluetoothradio.c b/src/modules/bluetoothradio/bluetoothradio.c index 713931ab9e..594b00c298 100644 --- a/src/modules/bluetoothradio/bluetoothradio.c +++ b/src/modules/bluetoothradio/bluetoothradio.c @@ -113,6 +113,7 @@ bool ffPrintBluetoothRadio(FFBluetoothRadioOptions* options) { } else { ffPrintError(FF_BLUETOOTHRADIO_DISPLAY_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "No devices detected"); } + return false; } FF_LIST_FOR_EACH (FFBluetoothRadioResult, radio, radios) { diff --git a/src/modules/cpu/cpu.c b/src/modules/cpu/cpu.c index 0d3803af31..57b7d1f33a 100644 --- a/src/modules/cpu/cpu.c +++ b/src/modules/cpu/cpu.c @@ -102,6 +102,10 @@ bool ffPrintCPU(FFCPUOptions* options) { FF_ARG(cpu.packages, "packages"), FF_ARG(cpu.march, "march"), FF_ARG(cpu.numaNodes, "numa-nodes"), + #if __i386__ || __x86_64__ + FF_ARG(cpu.codeName, "code-name"), + FF_ARG(cpu.technology, "technology"), + #endif })); } success = true; @@ -214,6 +218,20 @@ bool ffGenerateCPUJsonResult(FFCPUOptions* options, yyjson_mut_doc* doc, yyjson_ yyjson_mut_obj_add_null(doc, obj, "numaNodes"); } + #if __i386__ || __x86_64__ + if (cpu.codeName) { + yyjson_mut_obj_add_str(doc, obj, "codeName", cpu.codeName); + } else { + yyjson_mut_obj_add_null(doc, obj, "codeName"); + } + + if (cpu.technology) { + yyjson_mut_obj_add_str(doc, obj, "technology", cpu.technology); + } else { + yyjson_mut_obj_add_null(doc, obj, "technology"); + } + #endif + success = true; } @@ -228,7 +246,7 @@ void ffInitCPUOptions(FFCPUOptions* options) { ffStrbufInit(&options->tempSensor); options->temp = false; options->tempConfig = (FFColorRangeConfig) { 60, 80 }; - options->showPeCoreCount = false; + options->showPeCoreCount = true; } void ffDestroyCPUOptions(FFCPUOptions* options) { @@ -258,5 +276,9 @@ FFModuleBaseInfo ffCPUModuleInfo = { { "Processor package count", "packages" }, { "CPU microarchitecture", "march" }, { "NUMA node count", "numa-nodes" }, + #if __i386__ || __x86_64__ + { "CPU code name", "code-name" }, + { "CPU technology", "technology" }, + #endif })) }; diff --git a/src/modules/display/display.c b/src/modules/display/display.c index b11a2aabc2..be3d66f75a 100644 --- a/src/modules/display/display.c +++ b/src/modules/display/display.c @@ -166,14 +166,6 @@ bool ffPrintDisplay(FFDisplayOptions* options) { preferredRefreshRate[0] = 0; } - char buf[32]; - if (result->serial) { - const uint8_t* nums = (uint8_t*) &result->serial; - snprintf(buf, ARRAY_SIZE(buf), "%2X-%2X-%2X-%2X", nums[0], nums[1], nums[2], nums[3]); - } else { - buf[0] = '\0'; - } - FF_PRINT_FORMAT_CHECKED(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY, ((FFformatarg[]) { FF_ARG(result->width, "width"), FF_ARG(result->height, "height"), @@ -192,7 +184,7 @@ bool ffPrintDisplay(FFDisplayOptions* options) { FF_ARG(hdrEnabled, "hdr-enabled"), FF_ARG(result->manufactureYear, "manufacture-year"), FF_ARG(result->manufactureWeek, "manufacture-week"), - FF_ARG(buf, "serial"), + FF_ARG(result->serial, "serial"), FF_ARG(result->platformApi, "platform-api"), FF_ARG(hdrCompatible, "hdr-compatible"), FF_ARG(scaleFactor, "scale-factor"), @@ -395,8 +387,8 @@ bool ffGenerateDisplayJsonResult(FF_A_UNUSED FFDisplayOptions* options, yyjson_m yyjson_mut_obj_add_null(doc, obj, "manufactureDate"); } - if (item->serial) { - yyjson_mut_obj_add_uint(doc, obj, "serial", item->serial); + if (item->serial.length) { + yyjson_mut_obj_add_strbuf(doc, obj, "serial", &item->serial); } else { yyjson_mut_obj_add_null(doc, obj, "serial"); } diff --git a/src/modules/gpu/gpu.c b/src/modules/gpu/gpu.c index b0ace20006..032474f044 100644 --- a/src/modules/gpu/gpu.c +++ b/src/modules/gpu/gpu.c @@ -139,6 +139,12 @@ static void printGPUResult(FFGPUOptions* options, uint8_t index, const FFGPUResu } } + char maxSpeed[32] = "", currSpeed[32] = ""; + if (gpu->pcieSpeed != FF_GPU_PCIE_SPEED_UNSET) { + snprintf(maxSpeed, sizeof(maxSpeed), "%d x%d", gpu->psMax.gen, gpu->psMax.lanes); + snprintf(currSpeed, sizeof(currSpeed), "%d x%d", gpu->psCurr.gen, gpu->psCurr.lanes); + } + FF_PRINT_FORMAT_CHECKED(FF_GPU_MODULE_NAME, index, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) { FF_ARG(gpu->vendor, "vendor"), FF_ARG(gpu->name, "name"), @@ -160,6 +166,8 @@ static void printGPUResult(FFGPUOptions* options, uint8_t index, const FFGPUResu FF_ARG(coreUsageNum, "core-usage-num"), FF_ARG(coreUsageBar, "core-usage-bar"), FF_ARG(gpu->memoryType, "memory-type"), + FF_ARG(maxSpeed, "pcie-max-speed"), + FF_ARG(currSpeed, "pcie-curr-speed"), })); } } @@ -196,10 +204,6 @@ bool ffPrintGPU(FFGPUOptions* options) { ++i; } - if (selectedGPUs.length == 0) { - ffPrintError(FF_GPU_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "No GPUs found"); - } - FF_LIST_FOR_EACH (FFGPUResult, gpu, gpus) { ffStrbufDestroy(&gpu->vendor); ffStrbufDestroy(&gpu->name); @@ -208,6 +212,11 @@ bool ffPrintGPU(FFGPUOptions* options) { ffStrbufDestroy(&gpu->memoryType); } + if (selectedGPUs.length == 0) { + ffPrintError(FF_GPU_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, (gpus.length > 0 ? "GPUs found but all hidden by hideType option" : "No GPUs detected")); + return false; + } + return true; } @@ -230,11 +239,12 @@ void ffParseGPUJsonObject(FFGPUOptions* options, yyjson_val* module) { if (unsafe_yyjson_equals_str(key, "detectionMethod")) { int value; - const char* error = ffJsonConfigParseEnum(val, &value, (FFKeyValuePair[]) { + const char* error = ffJsonConfigParseEnum(val, &value, (FFKeyValuePair[]){ { "auto", FF_GPU_DETECTION_METHOD_AUTO }, { "pci", FF_GPU_DETECTION_METHOD_PCI }, { "vulkan", FF_GPU_DETECTION_METHOD_VULKAN }, { "opencl", FF_GPU_DETECTION_METHOD_OPENCL }, + { "egl-ext", FF_GPU_DETECTION_METHOD_EGL_EXT }, { "opengl", FF_GPU_DETECTION_METHOD_OPENGL }, {}, }); @@ -251,7 +261,7 @@ void ffParseGPUJsonObject(FFGPUOptions* options, yyjson_val* module) { options->hideType = FF_GPU_TYPE_NONE; } else { int value; - const char* error = ffJsonConfigParseEnum(val, &value, (FFKeyValuePair[]) { + const char* error = ffJsonConfigParseEnum(val, &value, (FFKeyValuePair[]){ { "none", FF_GPU_TYPE_NONE }, { "unknown", FF_GPU_TYPE_UNKNOWN }, { "integrated", FF_GPU_TYPE_INTEGRATED }, @@ -293,6 +303,9 @@ void ffGenerateGPUJsonConfig(FFGPUOptions* options, yyjson_mut_doc* doc, yyjson_ case FF_GPU_DETECTION_METHOD_OPENCL: yyjson_mut_obj_add_str(doc, module, "detectionMethod", "opencl"); break; + case FF_GPU_DETECTION_METHOD_EGL_EXT: + yyjson_mut_obj_add_str(doc, module, "detectionMethod", "egl-ext"); + break; case FF_GPU_DETECTION_METHOD_OPENGL: yyjson_mut_obj_add_str(doc, module, "detectionMethod", "opengl"); break; @@ -419,6 +432,18 @@ bool ffGenerateGPUJsonResult(FFGPUOptions* options, yyjson_mut_doc* doc, yyjson_ } yyjson_mut_obj_add_uint(doc, obj, "deviceId", gpu->deviceId); + + if (gpu->pcieSpeed != FF_GPU_PCIE_SPEED_UNSET) { + yyjson_mut_val* pcieSpeed = yyjson_mut_obj_add_obj(doc, obj, "pcieSpeed"); + yyjson_mut_val* maxSpeed = yyjson_mut_obj_add_obj(doc, pcieSpeed, "max"); + yyjson_mut_obj_add_uint(doc, maxSpeed, "gen", gpu->psMax.gen); + yyjson_mut_obj_add_uint(doc, maxSpeed, "lanes", gpu->psMax.lanes); + yyjson_mut_val* currSpeed = yyjson_mut_obj_add_obj(doc, pcieSpeed, "current"); + yyjson_mut_obj_add_uint(doc, currSpeed, "gen", gpu->psCurr.gen); + yyjson_mut_obj_add_uint(doc, currSpeed, "lanes", gpu->psCurr.lanes); + } else { + yyjson_mut_obj_add_null(doc, obj, "pcieSpeed"); + } } FF_LIST_FOR_EACH (FFGPUResult, gpu, gpus) { @@ -445,8 +470,8 @@ void ffInitGPUOptions(FFGPUOptions* options) { ; options->temp = false; options->hideType = FF_GPU_TYPE_NONE; - options->tempConfig = (FFColorRangeConfig) { 60, 80 }; - options->percent = (FFPercentageModuleConfig) { 50, 80, 0 }; + options->tempConfig = (FFColorRangeConfig){ 60, 80 }; + options->percent = (FFPercentageModuleConfig){ 50, 80, 0 }; } void ffDestroyGPUOptions(FFGPUOptions* options) { @@ -462,7 +487,7 @@ FFModuleBaseInfo ffGPUModuleInfo = { .printModule = (void*) ffPrintGPU, .generateJsonResult = (void*) ffGenerateGPUJsonResult, .generateJsonConfig = (void*) ffGenerateGPUJsonConfig, - .formatArgs = FF_FORMAT_ARG_LIST(((FFModuleFormatArg[]) { + .formatArgs = FF_FORMAT_ARG_LIST(((FFModuleFormatArg[]){ { "GPU vendor", "vendor" }, { "GPU name", "name" }, { "GPU driver", "driver" }, @@ -483,5 +508,7 @@ FFModuleBaseInfo ffGPUModuleInfo = { { "Core usage percentage num", "core-usage-num" }, { "Core usage percentage bar", "core-usage-bar" }, { "Memory type (Windows only)", "memory-type" }, + { "PCIe maximum speed in gen and lanes", "pcie-max-speed" }, + { "PCIe current speed in gen and lanes", "pcie-curr-speed" }, })), }; diff --git a/src/modules/gpu/option.h b/src/modules/gpu/option.h index 7ec0df33ed..4302b3402f 100644 --- a/src/modules/gpu/option.h +++ b/src/modules/gpu/option.h @@ -15,6 +15,7 @@ typedef enum FF_A_PACKED FFGPUDetectionMethod { FF_GPU_DETECTION_METHOD_PCI, FF_GPU_DETECTION_METHOD_VULKAN, FF_GPU_DETECTION_METHOD_OPENCL, + FF_GPU_DETECTION_METHOD_EGL_EXT, FF_GPU_DETECTION_METHOD_OPENGL, } FFGPUDetectionMethod; diff --git a/src/modules/monitor/monitor.c b/src/modules/monitor/monitor.c index 105ee67c62..636cd447b1 100644 --- a/src/modules/monitor/monitor.c +++ b/src/modules/monitor/monitor.c @@ -51,14 +51,6 @@ bool ffPrintMonitor(FFMonitorOptions* options) { } putchar('\n'); } else { - char buf[32]; - if (display->serial) { - const uint8_t* nums = (uint8_t*) &display->serial; - snprintf(buf, sizeof(buf), "%2X-%2X-%2X-%2X", nums[0], nums[1], nums[2], nums[3]); - } else { - buf[0] = '\0'; - } - FF_PRINT_FORMAT_CHECKED(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY, ((FFformatarg[]) { FF_ARG(display->name, "name"), FF_ARG(display->width, "width"), @@ -69,13 +61,13 @@ bool ffPrintMonitor(FFMonitorOptions* options) { FF_ARG(ppi, "ppi"), FF_ARG(display->manufactureYear, "manufacture-year"), FF_ARG(display->manufactureWeek, "manufacture-week"), - FF_ARG(buf, "serial"), + FF_ARG(display->serial, "serial"), FF_ARG(display->refreshRate, "refresh-rate"), FF_ARG(hdrCompatible, "hdr-compatible"), })); } - ffStrbufDestroy(&display->name); + // result is a singleton, so we don't destroy the members ++index; } diff --git a/src/modules/packages/option.h b/src/modules/packages/option.h index 1e895335a3..c215593c21 100644 --- a/src/modules/packages/option.h +++ b/src/modules/packages/option.h @@ -39,6 +39,8 @@ typedef enum FF_A_PACKED FFPackagesFlags { FF_PACKAGES_FLAG_MOSS_BIT = UINT64_C(1) << 32U, FF_PACKAGES_FLAG_APPIMAGE_BIT = UINT64_C(1) << 33U, FF_PACKAGES_FLAG_CARDS_BIT = UINT64_C(1) << 34U, + FF_PACKAGES_FLAG_PORG_BIT = UINT64_C(1) << 35U, + FF_PACKAGES_FLAG_INSTALLRELEASE_BIT = UINT64_C(1) << 36U, FF_PACKAGES_FLAG_FORCE_UNSIGNED = UINT64_MAX, } FFPackagesFlags; static_assert(sizeof(FFPackagesFlags) == sizeof(uint64_t), ""); diff --git a/src/modules/packages/packages.c b/src/modules/packages/packages.c index 4ef1d049af..8cb4027bde 100644 --- a/src/modules/packages/packages.c +++ b/src/modules/packages/packages.c @@ -89,6 +89,7 @@ bool ffPrintPackages(FFPackagesOptions* options) { } else { FF_PRINT_PACKAGE_NAME(hpkgSystem, "hpkg") } + FF_PRINT_PACKAGE_NAME(installrelease, "install-release") FF_PRINT_PACKAGE(kiss) FF_PRINT_PACKAGE(linglong) FF_PRINT_PACKAGE(lpkg) @@ -119,6 +120,7 @@ bool ffPrintPackages(FFPackagesOptions* options) { FF_PRINT_PACKAGE(pkg) FF_PRINT_PACKAGE(pkgsrc) FF_PRINT_PACKAGE(pkgtool) + FF_PRINT_PACKAGE(porg) FF_PRINT_PACKAGE(rpm) if (options->combined) { FF_PRINT_PACKAGE_ALL(scoop); @@ -144,29 +146,25 @@ bool ffPrintPackages(FFPackagesOptions* options) { &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) { - FF_ARG(counts.all, "all"), FF_ARG(counts.amSystem, "am-system"), FF_ARG(counts.amUser, "am-user"), FF_ARG(counts.appimage, "appimage"), FF_ARG(counts.apk, "apk"), FF_ARG(counts.brew, "brew"), - FF_ARG(brewAll, "brew-all"), FF_ARG(counts.brewCask, "brew-cask"), FF_ARG(counts.cards, "cards"), FF_ARG(counts.choco, "choco"), FF_ARG(counts.dpkg, "dpkg"), FF_ARG(counts.emerge, "emerge"), FF_ARG(counts.eopkg, "eopkg"), - FF_ARG(flatpakAll, "flatpak-all"), FF_ARG(counts.flatpakSystem, "flatpak-system"), FF_ARG(counts.flatpakUser, "flatpak-user"), - FF_ARG(guixAll, "guix-all"), FF_ARG(counts.guixHome, "guix-home"), FF_ARG(counts.guixSystem, "guix-system"), FF_ARG(counts.guixUser, "guix-user"), - FF_ARG(hpkgAll, "hpkg-all"), FF_ARG(counts.hpkgSystem, "hpkg-system"), FF_ARG(counts.hpkgUser, "hpkg-user"), + FF_ARG(counts.installrelease, "install-release"), FF_ARG(counts.kiss, "kiss"), FF_ARG(counts.linglong, "linglong"), FF_ARG(counts.lpkg, "lpkg"), @@ -174,7 +172,6 @@ bool ffPrintPackages(FFPackagesOptions* options) { FF_ARG(counts.macports, "macports"), FF_ARG(counts.mport, "mport"), FF_ARG(counts.moss, "moss"), - FF_ARG(nixAll, "nix-all"), FF_ARG(counts.nixDefault, "nix-default"), FF_ARG(counts.nixSystem, "nix-system"), FF_ARG(counts.nixUser, "nix-user"), @@ -187,6 +184,7 @@ bool ffPrintPackages(FFPackagesOptions* options) { FF_ARG(counts.pkg, "pkg"), FF_ARG(counts.pkgsrc, "pkgsrc"), FF_ARG(counts.pkgtool, "pkgtool"), + FF_ARG(counts.porg, "porg"), FF_ARG(counts.rpm, "rpm"), FF_ARG(counts.scoopGlobal, "scoop-global"), FF_ARG(counts.scoopUser, "scoop-user"), @@ -195,6 +193,13 @@ bool ffPrintPackages(FFPackagesOptions* options) { FF_ARG(counts.sorcery, "sorcery"), FF_ARG(counts.winget, "winget"), FF_ARG(counts.xbps, "xbps"), + + FF_ARG(brewAll, "brew-all"), + FF_ARG(flatpakAll, "flatpak-all"), + FF_ARG(guixAll, "guix-all"), + FF_ARG(hpkgAll, "hpkg-all"), + FF_ARG(nixAll, "nix-all"), + FF_ARG(counts.all, "all"), })); } @@ -279,6 +284,11 @@ void ffParsePackagesJsonObject(FFPackagesOptions* options, yyjson_val* module) { ; FF_TEST_PACKAGE_NAME(HPKG) break; + case 'I': + if (false) + ; + FF_TEST_PACKAGE_NAME(INSTALLRELEASE) + break; case 'K': if (false) ; @@ -318,6 +328,7 @@ void ffParsePackagesJsonObject(FFPackagesOptions* options, yyjson_val* module) { FF_TEST_PACKAGE_NAME(PKG) FF_TEST_PACKAGE_NAME(PKGSRC) FF_TEST_PACKAGE_NAME(PKGTOOL) + FF_TEST_PACKAGE_NAME(PORG) break; case 'R': if (false) @@ -401,6 +412,7 @@ void ffGeneratePackagesJsonConfig(FFPackagesOptions* options, yyjson_mut_doc* do FF_TEST_PACKAGE_NAME(PKG) FF_TEST_PACKAGE_NAME(PKGSRC) FF_TEST_PACKAGE_NAME(PKGTOOL) + FF_TEST_PACKAGE_NAME(PORG) FF_TEST_PACKAGE_NAME(RPM) FF_TEST_PACKAGE_NAME(SCOOP) FF_TEST_PACKAGE_NAME(SNAP) @@ -449,6 +461,7 @@ bool ffGeneratePackagesJsonResult(FFPackagesOptions* options, yyjson_mut_doc* do FF_APPEND_PACKAGE_COUNT(guixUser) FF_APPEND_PACKAGE_COUNT(hpkgSystem) FF_APPEND_PACKAGE_COUNT(hpkgUser) + FF_APPEND_PACKAGE_COUNT(installrelease) FF_APPEND_PACKAGE_COUNT(kiss) FF_APPEND_PACKAGE_COUNT(linglong) FF_APPEND_PACKAGE_COUNT(lpkg) @@ -467,6 +480,7 @@ bool ffGeneratePackagesJsonResult(FFPackagesOptions* options, yyjson_mut_doc* do FF_APPEND_PACKAGE_COUNT(pkg) FF_APPEND_PACKAGE_COUNT(pkgsrc) FF_APPEND_PACKAGE_COUNT(pkgtool) + FF_APPEND_PACKAGE_COUNT(porg) FF_APPEND_PACKAGE_COUNT(rpm) FF_APPEND_PACKAGE_COUNT(scoopGlobal) FF_APPEND_PACKAGE_COUNT(scoopUser) @@ -505,29 +519,25 @@ FFModuleBaseInfo ffPackagesModuleInfo = { .generateJsonResult = (void*) ffGeneratePackagesJsonResult, .generateJsonConfig = (void*) ffGeneratePackagesJsonConfig, .formatArgs = FF_FORMAT_ARG_LIST(((FFModuleFormatArg[]) { - { "Number of all packages", "all" }, { "Number of am-system packages", "am-system" }, { "Number of am-user (aka appman) packages", "am-user" }, { "Number of appimage packages", "appimage" }, { "Number of apk packages", "apk" }, { "Number of brew packages", "brew" }, - { "Total number of all brew packages", "brew-all" }, { "Number of brew-cask packages", "brew-cask" }, { "Number of cards packages", "cards" }, { "Number of choco packages", "choco" }, { "Number of dpkg packages", "dpkg" }, { "Number of emerge packages", "emerge" }, { "Number of eopkg packages", "eopkg" }, - { "Total number of all flatpak app packages", "flatpak-all" }, { "Number of flatpak-system app packages", "flatpak-system" }, { "Number of flatpak-user app packages", "flatpak-user" }, - { "Total number of all guix packages", "guix-all" }, { "Number of guix-home packages", "guix-home" }, { "Number of guix-system packages", "guix-system" }, { "Number of guix-user packages", "guix-user" }, - { "Total number of all hpkg packages", "hpkg-all" }, { "Number of hpkg-system packages", "hpkg-system" }, { "Number of hpkg-user packages", "hpkg-user" }, + { "Number of install-release packages", "install-release" }, { "Number of kiss packages", "kiss" }, { "Number of linglong packages", "linglong" }, { "Number of lpkg packages", "lpkg" }, @@ -535,7 +545,6 @@ FFModuleBaseInfo ffPackagesModuleInfo = { { "Number of macports packages", "macports" }, { "Number of mport packages", "mport" }, { "Number of moss packages", "moss" }, - { "Total number of all nix packages", "nix-all" }, { "Number of nix-default packages", "nix-default" }, { "Number of nix-system packages", "nix-system" }, { "Number of nix-user packages", "nix-user" }, @@ -548,6 +557,7 @@ FFModuleBaseInfo ffPackagesModuleInfo = { { "Number of pkg packages", "pkg" }, { "Number of pkgsrc packages", "pkgsrc" }, { "Number of pkgtool packages", "pkgtool" }, + { "Number of porg packages", "porg" }, { "Number of rpm packages", "rpm" }, { "Number of scoop-global packages", "scoop-global" }, { "Number of scoop-user packages", "scoop-user" }, @@ -556,5 +566,12 @@ FFModuleBaseInfo ffPackagesModuleInfo = { { "Number of sorcery packages", "sorcery" }, { "Number of winget packages", "winget" }, { "Number of xbps packages", "xbps" }, + + { "Total number of all brew packages", "brew-all" }, + { "Total number of all flatpak app packages", "flatpak-all" }, + { "Total number of all guix packages", "guix-all" }, + { "Total number of all hpkg packages", "hpkg-all" }, + { "Total number of all nix packages", "nix-all" }, + { "Number of all packages", "all" }, })) }; diff --git a/src/options/display.c b/src/options/display.c index ec80a37237..fe94819092 100644 --- a/src/options/display.c +++ b/src/options/display.c @@ -7,7 +7,7 @@ #include -const char* ffOptionsParseDisplayJsonConfig(FFOptionsDisplay* options, yyjson_val* root) { +const char* ffOptionsParseDisplayJsonConfig(FFOptionsDisplay* options, yyjson_val* root, yyjson_val** pkey) { yyjson_val* object = yyjson_obj_get(root, "display"); if (!object) { return NULL; @@ -19,6 +19,7 @@ const char* ffOptionsParseDisplayJsonConfig(FFOptionsDisplay* options, yyjson_va yyjson_val *key, *val; size_t idx, max; yyjson_obj_foreach (object, idx, max, key, val) { + *pkey = key; if (unsafe_yyjson_equals_str(key, "stat")) { if (yyjson_is_bool(val)) { if (yyjson_get_bool(val)) { @@ -833,11 +834,9 @@ void ffOptionsInitDisplay(FFOptionsDisplay* options) { options->showErrors = false; options->pipe = !isatty(STDOUT_FILENO) || !!getenv("NO_COLOR"); - -#ifdef NDEBUG - options->disableLinewrap = !options->pipe; -#else options->disableLinewrap = false; + +#ifndef NDEBUG options->debugMode = !!getenv("FF_DEBUG"); #endif diff --git a/src/options/display.h b/src/options/display.h index 8c674eabc7..6017291f50 100644 --- a/src/options/display.h +++ b/src/options/display.h @@ -90,7 +90,7 @@ typedef struct FFOptionsDisplay { FFlist constants; // list of FFstrbuf } FFOptionsDisplay; -const char* ffOptionsParseDisplayJsonConfig(FFOptionsDisplay* options, yyjson_val* root); +const char* ffOptionsParseDisplayJsonConfig(FFOptionsDisplay* options, yyjson_val* root, yyjson_val** pkey); bool ffOptionsParseDisplayCommandLine(FFOptionsDisplay* options, const char* key, const char* value); void ffOptionsInitDisplay(FFOptionsDisplay* options); void ffOptionsDestroyDisplay(FFOptionsDisplay* options); diff --git a/src/options/general.c b/src/options/general.c index 6257a0f174..1e1355df8a 100644 --- a/src/options/general.c +++ b/src/options/general.c @@ -6,7 +6,7 @@ #include -const char* ffOptionsParseGeneralJsonConfig(FFOptionsGeneral* options, yyjson_val* root) { +const char* ffOptionsParseGeneralJsonConfig(FFOptionsGeneral* options, yyjson_val* root, yyjson_val** pkey) { yyjson_val* object = yyjson_obj_get(root, "general"); if (!object) { return NULL; @@ -18,6 +18,7 @@ const char* ffOptionsParseGeneralJsonConfig(FFOptionsGeneral* options, yyjson_va yyjson_val *key, *val; size_t idx, max; yyjson_obj_foreach (object, idx, max, key, val) { + *pkey = key; if (unsafe_yyjson_equals_str(key, "thread")) { options->multithreading = yyjson_get_bool(val); } else if (unsafe_yyjson_equals_str(key, "processingTimeout")) { diff --git a/src/options/general.h b/src/options/general.h index 454ca60317..b58d6c9e34 100644 --- a/src/options/general.h +++ b/src/options/general.h @@ -20,7 +20,7 @@ typedef struct FFOptionsGeneral { #endif } FFOptionsGeneral; -const char* ffOptionsParseGeneralJsonConfig(FFOptionsGeneral* options, yyjson_val* root); +const char* ffOptionsParseGeneralJsonConfig(FFOptionsGeneral* options, yyjson_val* root, yyjson_val** pkey); bool ffOptionsParseGeneralCommandLine(FFOptionsGeneral* options, const char* key, const char* value); void ffOptionsInitGeneral(FFOptionsGeneral* options); void ffOptionsDestroyGeneral(FFOptionsGeneral* options); diff --git a/src/options/logo.c b/src/options/logo.c index 6205b8ea8c..99e22c99c6 100644 --- a/src/options/logo.c +++ b/src/options/logo.c @@ -20,11 +20,13 @@ void ffOptionsInitLogo(FFOptionsLogo* options) { options->recache = false; options->position = FF_LOGO_POSITION_LEFT; +#if FF_HAVE_CHAFA options->chafaFgOnly = false; ffStrbufInitStatic(&options->chafaSymbols, "block+border+space-wide-inverted"); // Chafa default options->chafaCanvasMode = UINT32_MAX; options->chafaColorSpace = UINT32_MAX; options->chafaDitherMode = UINT32_MAX; +#endif } bool ffOptionsParseLogoCommandLine(FFOptionsLogo* options, const char* key, const char* value) { @@ -157,6 +159,7 @@ bool ffOptionsParseLogoCommandLine(FFOptionsLogo* options, const char* key, cons ffOptionParseString(key, value, &options->source); options->type = FF_LOGO_TYPE_IMAGE_RAW; } else if ((subKey = ffOptionTestPrefix(key, "chafa"))) { +#if FF_HAVE_CHAFA if (subKey[0] == '\0') { ffOptionParseString(key, value, &options->source); options->type = FF_LOGO_TYPE_IMAGE_CHAFA; @@ -192,6 +195,10 @@ bool ffOptionsParseLogoCommandLine(FFOptionsLogo* options, const char* key, cons } else { return false; } +#else + fputs("Error: Chafa options are not supported because Fastfetch was built without Chafa support\n", stderr); + exit(477); +#endif } else { return false; } @@ -201,13 +208,15 @@ bool ffOptionsParseLogoCommandLine(FFOptionsLogo* options, const char* key, cons void ffOptionsDestroyLogo(FFOptionsLogo* options) { ffStrbufDestroy(&options->source); +#if FF_HAVE_CHAFA ffStrbufDestroy(&options->chafaSymbols); +#endif for (uint8_t i = 0; i < (uint8_t) FASTFETCH_LOGO_MAX_COLORS; ++i) { ffStrbufDestroy(&options->colors[i]); } } -const char* ffOptionsParseLogoJsonConfig(FFOptionsLogo* options, yyjson_val* root) { +const char* ffOptionsParseLogoJsonConfig(FFOptionsLogo* options, yyjson_val* root, yyjson_val** pkey) { yyjson_val* object = yyjson_obj_get(root, "logo"); if (!object) { return NULL; @@ -233,6 +242,7 @@ const char* ffOptionsParseLogoJsonConfig(FFOptionsLogo* options, yyjson_val* roo yyjson_val *key, *val; size_t idx, max; yyjson_obj_foreach (object, idx, max, key, val) { + *pkey = key; if (unsafe_yyjson_equals_str(key, "type")) { int value; const char* error = ffJsonConfigParseEnum(val, &value, (FFKeyValuePair[]) { @@ -343,6 +353,7 @@ const char* ffOptionsParseLogoJsonConfig(FFOptionsLogo* options, yyjson_val* roo options->position = (FFLogoPosition) value; continue; } else if (unsafe_yyjson_equals_str(key, "chafa")) { +#if FF_HAVE_CHAFA if (!yyjson_is_obj(val)) { return "Chafa config must be an object"; } @@ -409,6 +420,9 @@ const char* ffOptionsParseLogoJsonConfig(FFOptionsLogo* options, yyjson_val* roo options->chafaDitherMode = (uint32_t) value; } continue; +#else + return "Chafa options are not supported because Fastfetch was built without Chafa support"; +#endif } else { return "Unknown logo key"; } @@ -515,6 +529,7 @@ void ffOptionsGenerateLogoJsonConfig(FFdata* data, FFOptionsLogo* options) { "right", })[options->position]); +#if FF_HAVE_CHAFA { yyjson_mut_val* chafa = yyjson_mut_obj(doc); yyjson_mut_obj_add_bool(doc, chafa, "fgOnly", options->chafaFgOnly); @@ -547,6 +562,7 @@ void ffOptionsGenerateLogoJsonConfig(FFdata* data, FFOptionsLogo* options) { yyjson_mut_obj_add_val(doc, obj, "chafa", chafa); } +#endif yyjson_mut_obj_add_val(doc, doc->root, "logo", obj); } diff --git a/src/options/logo.h b/src/options/logo.h index 21b63fff77..7a71531d9c 100644 --- a/src/options/logo.h +++ b/src/options/logo.h @@ -45,15 +45,17 @@ typedef struct FFOptionsLogo { bool preserveAspectRatio; bool recache; +#if FF_HAVE_CHAFA bool chafaFgOnly; FFstrbuf chafaSymbols; uint32_t chafaCanvasMode; uint32_t chafaColorSpace; uint32_t chafaDitherMode; +#endif } FFOptionsLogo; void ffOptionsInitLogo(FFOptionsLogo* options); bool ffOptionsParseLogoCommandLine(FFOptionsLogo* options, const char* key, const char* value); void ffOptionsDestroyLogo(FFOptionsLogo* options); -const char* ffOptionsParseLogoJsonConfig(FFOptionsLogo* options, yyjson_val* root); +const char* ffOptionsParseLogoJsonConfig(FFOptionsLogo* options, yyjson_val* root, yyjson_val** pkey); void ffOptionsGenerateLogoJsonConfig(FFdata* data, FFOptionsLogo* options);