(HardwareInfo) Added Cpuid to the public interface
Also improved the code Former-commit-id: 07025657e01ff21a3581204ce74e180c3a5e7737
This commit is contained in:
parent
60b6b2f4de
commit
a67d66bbd8
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
NzHardwareInfoImpl::Cpuid(0x80000001, result);
|
// Récupération des capacités étendues du processeur (ECX et EDX, fonction 0x80000001)
|
||||||
s_capabilities[nzProcessorCap_x64] = (result[3] & (1U << 29)) != 0;
|
NzHardwareInfoImpl::Cpuid(0x80000001, 0, registers);
|
||||||
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)
|
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)
|
||||||
{
|
{
|
||||||
|
// 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];
|
char* ptr = &s_brandString[0];
|
||||||
for (nzUInt32 code = 0x80000002; code <= 0x80000004; ++code)
|
for (nzUInt32 code = 0x80000002; code <= 0x80000004; ++code)
|
||||||
{
|
{
|
||||||
NzHardwareInfoImpl::Cpuid(code, result);
|
NzHardwareInfoImpl::Cpuid(code, 0, registers);
|
||||||
std::memcpy(ptr, &result[0], 16);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NzHardwareInfo::IsCpuidSupported()
|
||||||
|
{
|
||||||
|
return NzHardwareInfoImpl::IsCpuidSupported();
|
||||||
|
}
|
||||||
|
|
||||||
bool NzHardwareInfo::IsInitialized()
|
bool NzHardwareInfo::IsInitialized()
|
||||||
{
|
{
|
||||||
return s_initialized;
|
return s_initialized;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue