From 102e8fcc72891b822045c28d490a40d1d4cf033d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 12 Jul 2025 23:36:04 +0800 Subject: [PATCH] GPU (Windows): detect GPU frequency by default Supported on Windows 11 only --- src/detection/gpu/gpu_windows.c | 36 ++++++++++++-- src/util/windows/nt.h | 87 +++++++++++++++++++++++++++++++-- 2 files changed, 116 insertions(+), 7 deletions(-) diff --git a/src/detection/gpu/gpu_windows.c b/src/detection/gpu/gpu_windows.c index cf6cdb4ff..b879c9386 100644 --- a/src/detection/gpu/gpu_windows.c +++ b/src/detection/gpu/gpu_windows.c @@ -241,6 +241,39 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* else if (adapterType.HybridIntegrated) gpu->type = FF_GPU_TYPE_INTEGRATED; } + + if (gpu->frequency == FF_GPU_FREQUENCY_UNSET) + { + for (ULONG nodeIdx = 0; ; nodeIdx++) + { + D3DKMT_NODEMETADATA nodeMetadata = { + .NodeOrdinalAndAdapterIndex = (0 << 16) | nodeIdx, + }; + queryAdapterInfo = (D3DKMT_QUERYADAPTERINFO) { + .hAdapter = openAdapterFromLuid.hAdapter, + .Type = KMTQAITYPE_NODEMETADATA, + .pPrivateDriverData = &nodeMetadata, + .PrivateDriverDataSize = sizeof(nodeMetadata), + }; + if (!NT_SUCCESS(D3DKMTQueryAdapterInfo(&queryAdapterInfo))) break; // Windows 10 and later + if (nodeMetadata.NodeData.EngineType != DXGK_ENGINE_TYPE_3D) continue; + + D3DKMT_QUERYSTATISTICS queryStatistics = { + .Type = D3DKMT_QUERYSTATISTICS_NODE2, + .AdapterLuid = *(LUID*)&adapterLuid, + .QueryNode2 = { .PhysicalAdapterIndex = 0, .NodeOrdinal = (UINT16) nodeIdx }, + }; + if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) // Windows 11 (22H2) and later + { + gpu->frequency = (uint32_t) (queryStatistics.QueryResult.NodeInformation.NodePerfData.MaxFrequency / 1000 / 1000); + break; + } + } + } + + D3DKMT_CLOSEADAPTER closeAdapter = { .hAdapter = openAdapterFromLuid.hAdapter }; + (void) D3DKMTCloseAdapter(&closeAdapter); + openAdapterFromLuid.hAdapter = 0; } if (options->temp && gpu->temperature != gpu->temperature) @@ -254,9 +287,6 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* queryStatistics.QueryResult.PhysAdapterInformation.AdapterPerfData.Temperature != 0) gpu->temperature = queryStatistics.QueryResult.PhysAdapterInformation.AdapterPerfData.Temperature / 10.0; } - - D3DKMT_CLOSEADAPTER closeAdapter = { .hAdapter = openAdapterFromLuid.hAdapter }; - (void) D3DKMTCloseAdapter(&closeAdapter); } } } diff --git a/src/util/windows/nt.h b/src/util/windows/nt.h index c1b854ebb..f56876d34 100644 --- a/src/util/windows/nt.h +++ b/src/util/windows/nt.h @@ -72,7 +72,8 @@ typedef struct _D3DKMT_ADAPTERTYPE typedef enum _KMTQUERYADAPTERINFOTYPE { - KMTQAITYPE_ADAPTERTYPE = 15, + KMTQAITYPE_ADAPTERTYPE = 15, // WDDM 1.2, Windows 8 + KMTQAITYPE_NODEMETADATA = 25, // WDDM 2.0, Windows 10 } KMTQUERYADAPTERINFOTYPE; typedef struct _D3DKMT_QUERYADAPTERINFO { @@ -82,16 +83,21 @@ typedef struct _D3DKMT_QUERYADAPTERINFO UINT PrivateDriverDataSize; } D3DKMT_QUERYADAPTERINFO; EXTERN_C _Check_return_ NTSTATUS APIENTRY D3DKMTQueryAdapterInfo(_Inout_ CONST D3DKMT_QUERYADAPTERINFO*); -#endif typedef enum _D3DKMT_QUERYSTATISTICS_TYPE { D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER = 10, // WDDM 2.4, Windows 10 April 2018 Update (version 1803) + D3DKMT_QUERYSTATISTICS_NODE2 = 18, // WDDM 3.1, Windows 11 2022 Update (version 22H2) } D3DKMT_QUERYSTATISTICS_TYPE; typedef struct _D3DKMT_QUERYSTATISTICS_QUERY_PHYSICAL_ADAPTER { ULONG PhysicalAdapterIndex; } D3DKMT_QUERYSTATISTICS_QUERY_PHYSICAL_ADAPTER; +typedef struct _D3DKMT_QUERYSTATISTICS_QUERY_NODE2 +{ + UINT16 PhysicalAdapterIndex; + UINT16 NodeOrdinal; +} D3DKMT_QUERYSTATISTICS_QUERY_NODE2; typedef struct _D3DKMT_ADAPTER_PERFDATA { UINT32 PhysicalAdapterIndex; // in: The physical adapter index, in an LDA chain @@ -128,9 +134,32 @@ typedef struct _D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER_INFORMATION D3DKMT_ADAPTER_PERFDATACAPS AdapterPerfDataCaps; D3DKMT_GPUVERSION GpuVersion; } D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER_INFORMATION; +typedef struct _D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION { + D3DKMT_ALIGN64 UINT64 Reserved[34]; +} D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION; +typedef struct _D3DKMT_NODE_PERFDATA +{ + UINT32 NodeOrdinal; // in: Node ordinal of the requested engine. + UINT32 PhysicalAdapterIndex; // in: The physical adapter index, in an LDA chain + D3DKMT_ALIGN64 ULONGLONG Frequency; // out: Clock frequency of the engine in hertz + D3DKMT_ALIGN64 ULONGLONG MaxFrequency; // out: Max engine clock frequency + D3DKMT_ALIGN64 ULONGLONG MaxFrequencyOC;// out: Max engine over clock frequency + ULONG Voltage; // out: Voltage of the engine in milli volts mV + ULONG VoltageMax; // out: Max voltage levels in milli volts. + ULONG VoltageMaxOC; // out: Max voltage level while overclocked in milli volts. + // WDDM 2.5 + D3DKMT_ALIGN64 ULONGLONG MaxTransitionLatency; // out: Max transition latency to change the frequency in 100 nanoseconds +} D3DKMT_NODE_PERFDATA; +typedef struct _D3DKMT_QUERYSTATISTICS_NODE_INFORMATION { + D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION GlobalInformation; //Global statistics + D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION SystemInformation; //Statistics for system thread + D3DKMT_NODE_PERFDATA NodePerfData; + UINT32 Reserved[3]; +} D3DKMT_QUERYSTATISTICS_NODE_INFORMATION; typedef union _D3DKMT_QUERYSTATISTICS_RESULT { - D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER_INFORMATION PhysAdapterInformation; // in: id of physical adapter to get statistics for + D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER_INFORMATION PhysAdapterInformation; + D3DKMT_QUERYSTATISTICS_NODE_INFORMATION NodeInformation; uint8_t Padding[776]; } D3DKMT_QUERYSTATISTICS_RESULT; typedef struct _D3DKMT_QUERYSTATISTICS @@ -142,8 +171,58 @@ typedef struct _D3DKMT_QUERYSTATISTICS union { - D3DKMT_QUERYSTATISTICS_QUERY_PHYSICAL_ADAPTER QueryPhysAdapter; + D3DKMT_QUERYSTATISTICS_QUERY_PHYSICAL_ADAPTER QueryPhysAdapter; // in: id of physical adapter to get statistics for + D3DKMT_QUERYSTATISTICS_QUERY_NODE2 QueryNode2; // in: id of node to get statistics for }; } D3DKMT_QUERYSTATISTICS; static_assert(sizeof(D3DKMT_QUERYSTATISTICS) == 0x328, "D3DKMT_QUERYSTATISTICS structure size mismatch"); EXTERN_C _Check_return_ NTSTATUS APIENTRY D3DKMTQueryStatistics(_In_ CONST D3DKMT_QUERYSTATISTICS*); + +#define DXGK_MAX_METADATA_NAME_LENGTH 32 +typedef enum +{ + DXGK_ENGINE_TYPE_OTHER, + DXGK_ENGINE_TYPE_3D, + DXGK_ENGINE_TYPE_VIDEO_DECODE, + DXGK_ENGINE_TYPE_VIDEO_ENCODE, + DXGK_ENGINE_TYPE_VIDEO_PROCESSING, + DXGK_ENGINE_TYPE_SCENE_ASSEMBLY, + DXGK_ENGINE_TYPE_COPY, + DXGK_ENGINE_TYPE_OVERLAY, + DXGK_ENGINE_TYPE_CRYPTO, + DXGK_ENGINE_TYPE_VIDEO_CODEC, + DXGK_ENGINE_TYPE_MAX +} DXGK_ENGINE_TYPE; +typedef struct _DXGK_NODEMETADATA_FLAGS +{ + union + { + struct + { + UINT ContextSchedulingSupported : 1; // WDDM 2.2 + UINT RingBufferFenceRelease : 1; // WDDM 2.5 + UINT SupportTrackedWorkload : 1; + UINT UserModeSubmission : 1; + UINT SupportBuildTestCommandBuffer : 1; // WDDM 3.2 + UINT Reserved : 11; + UINT MaxInFlightHwQueueBuffers : 16; + }; + UINT32 Value; + }; +} DXGK_NODEMETADATA_FLAGS; +typedef struct _DXGK_NODEMETADATA +{ + DXGK_ENGINE_TYPE EngineType; + WCHAR FriendlyName[DXGK_MAX_METADATA_NAME_LENGTH]; + DXGK_NODEMETADATA_FLAGS Flags; // WDDM 2.2 + BOOLEAN GpuMmuSupported; // WDDM 2.0 ??? + BOOLEAN IoMmuSupported; +} __attribute__((packed)) DXGK_NODEMETADATA; +typedef struct _D3DKMT_NODEMETADATA +{ + _In_ UINT NodeOrdinalAndAdapterIndex; // WDDMv2: High word is physical adapter index, low word is node ordinal + _Out_ DXGK_NODEMETADATA NodeData; +} __attribute__((packed)) D3DKMT_NODEMETADATA; +static_assert(sizeof(D3DKMT_NODEMETADATA) == 0x4E, "D3DKMT_NODEMETADATA structure size mismatch"); + +#endif