From a67d66bbd8594a3f0bef5d89b020ac7999e85193 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 24 Feb 2015 17:28:02 +0100 Subject: [PATCH] (HardwareInfo) Added Cpuid to the public interface Also improved the code Former-commit-id: 07025657e01ff21a3581204ce74e180c3a5e7737 --- include/Nazara/Core/HardwareInfo.hpp | 3 + src/Nazara/Core/HardwareInfo.cpp | 97 +++++++++++++--------- src/Nazara/Core/Win32/HardwareInfoImpl.cpp | 9 +- src/Nazara/Core/Win32/HardwareInfoImpl.hpp | 2 +- 4 files changed, 69 insertions(+), 42 deletions(-) diff --git a/include/Nazara/Core/HardwareInfo.hpp b/include/Nazara/Core/HardwareInfo.hpp index 575b3ebc9..73f0c9eb8 100644 --- a/include/Nazara/Core/HardwareInfo.hpp +++ b/include/Nazara/Core/HardwareInfo.hpp @@ -14,6 +14,8 @@ class NAZARA_API NzHardwareInfo { public: + static void Cpuid(nzUInt32 functionId, nzUInt32 subFunctionId, nzUInt32 result[4]); + static NzString GetProcessorBrandString(); static unsigned int GetProcessorCount(); static nzProcessorVendor GetProcessorVendor(); @@ -23,6 +25,7 @@ class NAZARA_API NzHardwareInfo static bool Initialize(); + static bool IsCpuidSupported(); static bool IsInitialized(); static void Uninitialize(); diff --git a/src/Nazara/Core/HardwareInfo.cpp b/src/Nazara/Core/HardwareInfo.cpp index 0309dd522..762012b8f 100644 --- a/src/Nazara/Core/HardwareInfo.cpp +++ b/src/Nazara/Core/HardwareInfo.cpp @@ -78,7 +78,11 @@ namespace bool s_initialized = false; char s_brandString[48] = "Not initialized"; - char s_vendor[12] = {'C', 'P', 'U', 'i', 's', 'U', 'n', 'k', 'n', 'o', 'w', 'n'}; +} + +void NzHardwareInfo::Cpuid(nzUInt32 functionId, nzUInt32 subFunctionId, nzUInt32 result[4]) +{ + return NzHardwareInfoImpl::Cpuid(functionId, subFunctionId, result); } NzString NzHardwareInfo::GetProcessorBrandString() @@ -138,67 +142,86 @@ bool NzHardwareInfo::Initialize() s_initialized = true; - nzUInt32 result[4]; + nzUInt32 registers[4]; // Récupère les quatre registres (EAX, EBX, ECX et EDX) - NzHardwareInfoImpl::Cpuid(0, result); - std::memcpy(&s_vendor[0], &result[1], 4); - std::memcpy(&s_vendor[4], &result[3], 4); - std::memcpy(&s_vendor[8], &result[2], 4); + // Pour plus de clarté + nzUInt32& eax = registers[0]; + nzUInt32& ebx = registers[1]; + nzUInt32& ecx = registers[2]; + nzUInt32& edx = registers[3]; + + // Pour commencer, on va récupérer l'identifiant du constructeur ainsi que l'id de fonction maximal supporté par le CPUID + NzHardwareInfoImpl::Cpuid(0, 0, registers); + + // Attention à l'ordre : EBX, EDX, ECX + nzUInt32 manufacturerId[3] = {ebx, edx, ecx}; // Identification du concepteur s_vendorEnum = nzProcessorVendor_Unknown; for (const VendorString& vendorString : vendorStrings) { - if (std::memcmp(s_vendor, vendorString.vendor, 12) == 0) + if (std::memcmp(manufacturerId, vendorString.vendor, 12) == 0) { s_vendorEnum = vendorString.vendorEnum; break; } } - unsigned int ids = result[0]; - - if (ids >= 1) + if (eax >= 1) { - NzHardwareInfoImpl::Cpuid(1, result); - s_capabilities[nzProcessorCap_AVX] = (result[2] & (1U << 28)) != 0; - s_capabilities[nzProcessorCap_FMA3] = (result[2] & (1U << 12)) != 0; - s_capabilities[nzProcessorCap_MMX] = (result[3] & (1U << 23)) != 0; - s_capabilities[nzProcessorCap_SSE] = (result[3] & (1U << 25)) != 0; - s_capabilities[nzProcessorCap_SSE2] = (result[3] & (1U << 26)) != 0; - s_capabilities[nzProcessorCap_SSE3] = (result[2] & (1U << 0)) != 0; - s_capabilities[nzProcessorCap_SSSE3] = (result[2] & (1U << 9)) != 0; - s_capabilities[nzProcessorCap_SSE41] = (result[2] & (1U << 19)) != 0; - s_capabilities[nzProcessorCap_SSE42] = (result[2] & (1U << 20)) != 0; + // Récupération de certaines capacités du processeur (ECX et EDX, fonction 1) + NzHardwareInfoImpl::Cpuid(1, 0, registers); - NzHardwareInfoImpl::Cpuid(0x80000000, result); - unsigned int exIds = result[0]; + s_capabilities[nzProcessorCap_AVX] = (ecx & (1U << 28)) != 0; + s_capabilities[nzProcessorCap_FMA3] = (ecx & (1U << 12)) != 0; + s_capabilities[nzProcessorCap_MMX] = (edx & (1U << 23)) != 0; + s_capabilities[nzProcessorCap_SSE] = (edx & (1U << 25)) != 0; + s_capabilities[nzProcessorCap_SSE2] = (edx & (1U << 26)) != 0; + s_capabilities[nzProcessorCap_SSE3] = (ecx & (1U << 0)) != 0; + s_capabilities[nzProcessorCap_SSSE3] = (ecx & (1U << 9)) != 0; + s_capabilities[nzProcessorCap_SSE41] = (ecx & (1U << 19)) != 0; + s_capabilities[nzProcessorCap_SSE42] = (ecx & (1U << 20)) != 0; + } - if (exIds >= 0x80000001) + // Récupération de la plus grande fonction étendue supportée (EAX, fonction 0x80000000) + NzHardwareInfoImpl::Cpuid(0x80000000, 0, registers); + + nzUInt32 maxSupportedExtendedFunction = eax; + if (maxSupportedExtendedFunction >= 0x80000001) + { + // Récupération des capacités étendues du processeur (ECX et EDX, fonction 0x80000001) + NzHardwareInfoImpl::Cpuid(0x80000001, 0, registers); + + s_capabilities[nzProcessorCap_x64] = (edx & (1U << 29)) != 0; // Support du 64bits, indépendant de l'OS + s_capabilities[nzProcessorCap_FMA4] = (ecx & (1U << 16)) != 0; + s_capabilities[nzProcessorCap_SSE4a] = (ecx & (1U << 6)) != 0; + s_capabilities[nzProcessorCap_XOP] = (ecx & (1U << 11)) != 0; + + if (maxSupportedExtendedFunction >= 0x80000004) { - NzHardwareInfoImpl::Cpuid(0x80000001, result); - s_capabilities[nzProcessorCap_x64] = (result[3] & (1U << 29)) != 0; - s_capabilities[nzProcessorCap_FMA4] = (result[2] & (1U << 16)) != 0; - s_capabilities[nzProcessorCap_SSE4a] = (result[2] & (1U << 6)) != 0; - s_capabilities[nzProcessorCap_XOP] = (result[2] & (1U << 11)) != 0; - - if (exIds >= 0x80000004) + // Récupération d'une chaîne de caractère décrivant le processeur (EAX, EBX, ECX et EDX, + // fonctions de 0x80000002 à 0x80000004 compris) + char* ptr = &s_brandString[0]; + for (nzUInt32 code = 0x80000002; code <= 0x80000004; ++code) { - char* ptr = &s_brandString[0]; - for (nzUInt32 code = 0x80000002; code <= 0x80000004; ++code) - { - NzHardwareInfoImpl::Cpuid(code, result); - std::memcpy(ptr, &result[0], 16); + NzHardwareInfoImpl::Cpuid(code, 0, registers); + std::memcpy(ptr, ®isters[0], 4*sizeof(nzUInt32)); // On rajoute les 16 octets à la chaîne - ptr += 16; - } + ptr += 4*sizeof(nzUInt32); } + + // Le caractère nul faisant partie de la chaîne retournée par le CPUID, pas besoin de le rajouter } } return true; } +bool NzHardwareInfo::IsCpuidSupported() +{ + return NzHardwareInfoImpl::IsCpuidSupported(); +} + bool NzHardwareInfo::IsInitialized() { return s_initialized; diff --git a/src/Nazara/Core/Win32/HardwareInfoImpl.cpp b/src/Nazara/Core/Win32/HardwareInfoImpl.cpp index 482011d95..9eb37c232 100644 --- a/src/Nazara/Core/Win32/HardwareInfoImpl.cpp +++ b/src/Nazara/Core/Win32/HardwareInfoImpl.cpp @@ -12,17 +12,18 @@ #include -void NzHardwareInfoImpl::Cpuid(nzUInt32 code, nzUInt32 result[4]) +void NzHardwareInfoImpl::Cpuid(nzUInt32 functionId, nzUInt32 subFunctionId, nzUInt32 registers[4]) { #if defined(NAZARA_COMPILER_MSVC) static_assert(sizeof(nzUInt32) == sizeof(int), "Assertion failed"); - __cpuid(reinterpret_cast(result), static_cast(code)); // Visual propose une fonction intrinsèque pour le cpuid + // Visual propose une fonction intrinsèque pour le cpuid + __cpuidex(reinterpret_cast(registers), static_cast(functionId), static_cast(subFunctionId)); #elif defined(NAZARA_COMPILER_CLANG) || defined(NAZARA_COMPILER_GCC) || defined(NAZARA_COMPILER_INTEL) // Source: http://stackoverflow.com/questions/1666093/cpuid-implementations-in-c asm volatile ("cpuid" // Besoin d'être volatile ? - : "=a" (result[0]), "=b" (result[1]), "=c" (result[2]), "=d" (result[3]) // output - : "a" (code), "c" (0)); // input + : "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3]) // output + : "a" (functionId), "c" (subFunctionId)); // input #else NazaraInternalError("Cpuid has been called although it is not supported"); #endif diff --git a/src/Nazara/Core/Win32/HardwareInfoImpl.hpp b/src/Nazara/Core/Win32/HardwareInfoImpl.hpp index cd8f4264a..df8d9a5d7 100644 --- a/src/Nazara/Core/Win32/HardwareInfoImpl.hpp +++ b/src/Nazara/Core/Win32/HardwareInfoImpl.hpp @@ -12,7 +12,7 @@ class NzHardwareInfoImpl { public: - static void Cpuid(nzUInt32 code, nzUInt32 result[4]); + static void Cpuid(nzUInt32 functionId, nzUInt32 subFunctionId, nzUInt32 registers[4]); static unsigned int GetProcessorCount(); static bool IsCpuidSupported(); };