(HardwareInfo) Added Cpuid to the public interface

Also improved the code


Former-commit-id: 07025657e01ff21a3581204ce74e180c3a5e7737
This commit is contained in:
Lynix 2015-02-24 17:28:02 +01:00
parent 60b6b2f4de
commit a67d66bbd8
4 changed files with 69 additions and 42 deletions

View File

@ -14,6 +14,8 @@
class NAZARA_API NzHardwareInfo class NAZARA_API NzHardwareInfo
{ {
public: public:
static void Cpuid(nzUInt32 functionId, nzUInt32 subFunctionId, nzUInt32 result[4]);
static NzString GetProcessorBrandString(); static NzString GetProcessorBrandString();
static unsigned int GetProcessorCount(); static unsigned int GetProcessorCount();
static nzProcessorVendor GetProcessorVendor(); static nzProcessorVendor GetProcessorVendor();
@ -23,6 +25,7 @@ class NAZARA_API NzHardwareInfo
static bool Initialize(); static bool Initialize();
static bool IsCpuidSupported();
static bool IsInitialized(); static bool IsInitialized();
static void Uninitialize(); static void Uninitialize();

View File

@ -78,7 +78,11 @@ namespace
bool s_initialized = false; bool s_initialized = false;
char s_brandString[48] = "Not initialized"; 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() NzString NzHardwareInfo::GetProcessorBrandString()
@ -138,67 +142,86 @@ bool NzHardwareInfo::Initialize()
s_initialized = true; s_initialized = true;
nzUInt32 result[4]; nzUInt32 registers[4]; // Récupère les quatre registres (EAX, EBX, ECX et EDX)
NzHardwareInfoImpl::Cpuid(0, result); // Pour plus de clarté
std::memcpy(&s_vendor[0], &result[1], 4); nzUInt32& eax = registers[0];
std::memcpy(&s_vendor[4], &result[3], 4); nzUInt32& ebx = registers[1];
std::memcpy(&s_vendor[8], &result[2], 4); 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 // Identification du concepteur
s_vendorEnum = nzProcessorVendor_Unknown; s_vendorEnum = nzProcessorVendor_Unknown;
for (const VendorString& vendorString : vendorStrings) 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; s_vendorEnum = vendorString.vendorEnum;
break; break;
} }
} }
unsigned int ids = result[0]; if (eax >= 1)
if (ids >= 1)
{ {
NzHardwareInfoImpl::Cpuid(1, result); // Récupération de certaines capacités du processeur (ECX et EDX, fonction 1)
s_capabilities[nzProcessorCap_AVX] = (result[2] & (1U << 28)) != 0; NzHardwareInfoImpl::Cpuid(1, 0, registers);
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;
NzHardwareInfoImpl::Cpuid(0x80000000, result); s_capabilities[nzProcessorCap_AVX] = (ecx & (1U << 28)) != 0;
unsigned int exIds = result[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); // Récupération d'une chaîne de caractère décrivant le processeur (EAX, EBX, ECX et EDX,
s_capabilities[nzProcessorCap_x64] = (result[3] & (1U << 29)) != 0; // fonctions de 0x80000002 à 0x80000004 compris)
s_capabilities[nzProcessorCap_FMA4] = (result[2] & (1U << 16)) != 0; char* ptr = &s_brandString[0];
s_capabilities[nzProcessorCap_SSE4a] = (result[2] & (1U << 6)) != 0; for (nzUInt32 code = 0x80000002; code <= 0x80000004; ++code)
s_capabilities[nzProcessorCap_XOP] = (result[2] & (1U << 11)) != 0;
if (exIds >= 0x80000004)
{ {
char* ptr = &s_brandString[0]; NzHardwareInfoImpl::Cpuid(code, 0, registers);
for (nzUInt32 code = 0x80000002; code <= 0x80000004; ++code) std::memcpy(ptr, &registers[0], 4*sizeof(nzUInt32)); // On rajoute les 16 octets à la chaîne
{
NzHardwareInfoImpl::Cpuid(code, result);
std::memcpy(ptr, &result[0], 16);
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; return true;
} }
bool NzHardwareInfo::IsCpuidSupported()
{
return NzHardwareInfoImpl::IsCpuidSupported();
}
bool NzHardwareInfo::IsInitialized() bool NzHardwareInfo::IsInitialized()
{ {
return s_initialized; return s_initialized;

View File

@ -12,17 +12,18 @@
#include <Nazara/Core/Debug.hpp> #include <Nazara/Core/Debug.hpp>
void NzHardwareInfoImpl::Cpuid(nzUInt32 code, nzUInt32 result[4]) void NzHardwareInfoImpl::Cpuid(nzUInt32 functionId, nzUInt32 subFunctionId, nzUInt32 registers[4])
{ {
#if defined(NAZARA_COMPILER_MSVC) #if defined(NAZARA_COMPILER_MSVC)
static_assert(sizeof(nzUInt32) == sizeof(int), "Assertion failed"); static_assert(sizeof(nzUInt32) == sizeof(int), "Assertion failed");
__cpuid(reinterpret_cast<int*>(result), static_cast<int>(code)); // Visual propose une fonction intrinsèque pour le cpuid // Visual propose une fonction intrinsèque pour le cpuid
__cpuidex(reinterpret_cast<int*>(registers), static_cast<int>(functionId), static_cast<int>(subFunctionId));
#elif defined(NAZARA_COMPILER_CLANG) || defined(NAZARA_COMPILER_GCC) || defined(NAZARA_COMPILER_INTEL) #elif defined(NAZARA_COMPILER_CLANG) || defined(NAZARA_COMPILER_GCC) || defined(NAZARA_COMPILER_INTEL)
// Source: http://stackoverflow.com/questions/1666093/cpuid-implementations-in-c // Source: http://stackoverflow.com/questions/1666093/cpuid-implementations-in-c
asm volatile ("cpuid" // Besoin d'être volatile ? asm volatile ("cpuid" // Besoin d'être volatile ?
: "=a" (result[0]), "=b" (result[1]), "=c" (result[2]), "=d" (result[3]) // output : "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3]) // output
: "a" (code), "c" (0)); // input : "a" (functionId), "c" (subFunctionId)); // input
#else #else
NazaraInternalError("Cpuid has been called although it is not supported"); NazaraInternalError("Cpuid has been called although it is not supported");
#endif #endif

View File

@ -12,7 +12,7 @@
class NzHardwareInfoImpl class NzHardwareInfoImpl
{ {
public: public:
static void Cpuid(nzUInt32 code, nzUInt32 result[4]); static void Cpuid(nzUInt32 functionId, nzUInt32 subFunctionId, nzUInt32 registers[4]);
static unsigned int GetProcessorCount(); static unsigned int GetProcessorCount();
static bool IsCpuidSupported(); static bool IsCpuidSupported();
}; };