From faee0b93b5e98c03c99724f59727cf40451853d0 Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 22 Nov 2012 11:07:02 +0100 Subject: [PATCH] Added HardwareInfo class Former-commit-id: 3db2f8f11d58b4b71b85f749ce2a12dcfff986bc --- include/Nazara/Core/Enums.hpp | 38 ++++++ include/Nazara/Core/HardwareInfo.hpp | 29 +++++ src/Nazara/Core/HardwareInfo.cpp | 142 +++++++++++++++++++++ src/Nazara/Core/Win32/HardwareInfoImpl.cpp | 82 ++++++++++++ src/Nazara/Core/Win32/HardwareInfoImpl.hpp | 20 +++ 5 files changed, 311 insertions(+) create mode 100644 include/Nazara/Core/HardwareInfo.hpp create mode 100644 src/Nazara/Core/HardwareInfo.cpp create mode 100644 src/Nazara/Core/Win32/HardwareInfoImpl.cpp create mode 100644 src/Nazara/Core/Win32/HardwareInfoImpl.hpp diff --git a/include/Nazara/Core/Enums.hpp b/include/Nazara/Core/Enums.hpp index b3bb1bb2e..7aee6c70d 100644 --- a/include/Nazara/Core/Enums.hpp +++ b/include/Nazara/Core/Enums.hpp @@ -7,6 +7,44 @@ #ifndef NAZARA_ENUMS_CORE_HPP #define NAZARA_ENUMS_CORE_HPP +enum nzProcessorCap +{ + nzProcessorCap_AVX, + nzProcessorCap_FMA3, + nzProcessorCap_FMA4, + nzProcessorCap_MMX, + nzProcessorCap_XOP, + nzProcessorCap_SSE, + nzProcessorCap_SSE2, + nzProcessorCap_SSE3, + nzProcessorCap_SSSE3, + nzProcessorCap_SSE41, + nzProcessorCap_SSE42, + nzProcessorCap_SSE4a, + + nzProcessorCap_Max = nzProcessorCap_SSE4a +}; + +enum nzProcessorVendor +{ + nzProcessorVendor_Unknown = -1, + + nzProcessorVendor_AMD, + nzProcessorVendor_Centaur, + nzProcessorVendor_Cyrix, + nzProcessorVendor_Intel, + nzProcessorVendor_Transmeta, + nzProcessorVendor_NSC, + nzProcessorVendor_NexGen, + nzProcessorVendor_Rise, + nzProcessorVendor_SIS, + nzProcessorVendor_UMC, + nzProcessorVendor_VIA, + nzProcessorVendor_Vortex, + + nzProcessorVendor_Max = nzProcessorVendor_Vortex +}; + enum nzEndianness { nzEndianness_Unknown = -1, diff --git a/include/Nazara/Core/HardwareInfo.hpp b/include/Nazara/Core/HardwareInfo.hpp new file mode 100644 index 000000000..d116db0a1 --- /dev/null +++ b/include/Nazara/Core/HardwareInfo.hpp @@ -0,0 +1,29 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine - Renderer module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_HARDWAREINFO_HPP +#define NAZARA_HARDWAREINFO_HPP + +#include +#include + +class NAZARA_API NzHardwareInfo +{ + public: + static unsigned int GetProcessorCount(); + static nzProcessorVendor GetProcessorVendor(); + static void GetProcessorVendor(char vendor[12]); + + static bool HasCapability(nzProcessorCap capability); + + static bool Initialize(); + + static bool Is64Bits(); + + static void Uninitialize(); +}; + +#endif // NAZARA_HARDWAREINFO_HPP diff --git a/src/Nazara/Core/HardwareInfo.cpp b/src/Nazara/Core/HardwareInfo.cpp new file mode 100644 index 000000000..f7695c3b5 --- /dev/null +++ b/src/Nazara/Core/HardwareInfo.cpp @@ -0,0 +1,142 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine - Core module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +#if defined(NAZARA_PLATFORM_WINDOWS) + #include +#elif defined(NAZARA_PLATFORM_POSIX) + #include +#else + #error Lack of implementation: HardwareInfo +#endif + +#include + +namespace +{ + nzProcessorVendor s_vendorEnum = nzProcessorVendor_Unknown; + bool s_capabilities[nzProcessorCap_Max+1] = {false}; + bool s_x64 = false; + + char s_vendor[12] = {'C', 'P', 'U', 'i', 's', 'U', 'n', 'k', 'n', 'o', 'w', 'n'}; + + struct VendorString + { + nzProcessorVendor vendorEnum; + char vendor[13]; // +1 pour le \0 automatiquement ajouté par le compilateur + }; +} + +unsigned int NzHardwareInfo::GetProcessorCount() +{ + static unsigned int processorCount = std::max(NzHardwareInfoImpl::GetProcessorCount(), 1U); + return processorCount; +} + +nzProcessorVendor NzHardwareInfo::GetProcessorVendor() +{ + return s_vendorEnum; +} + +void NzHardwareInfo::GetProcessorVendor(char vendor[12]) +{ + std::memcpy(vendor, s_vendor, 12); +} + +bool NzHardwareInfo::HasCapability(nzProcessorCap capability) +{ + #ifdef NAZARA_DEBUG + if (capability > nzProcessorCap_Max) + { + NazaraError("Capability type out of enum"); + return false; + } + #endif + + return s_capabilities[capability]; +} + +bool NzHardwareInfo::Initialize() +{ + if (!NzHardwareInfoImpl::IsCpuidSupported()) + return false; + + nzUInt32 result[4]; + + 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); + + VendorString s_vendorStrings[] = + { + {nzProcessorVendor_AMD, "AMDisbetter!"}, + {nzProcessorVendor_AMD, "AuthenticAMD"}, + {nzProcessorVendor_Centaur, "CentaurHauls"}, + {nzProcessorVendor_Cyrix, "CyrixInstead"}, + {nzProcessorVendor_Intel, "GenuineIntel"}, + {nzProcessorVendor_NexGen, "NexGenDriven"}, + {nzProcessorVendor_NSC, "Geode by NSC"}, + {nzProcessorVendor_SIS, "SiS SiS SiS "}, + {nzProcessorVendor_Transmeta, "GenuineTMx86"}, + {nzProcessorVendor_Transmeta, "TransmetaCPU"}, + {nzProcessorVendor_UMC, "UMC UMC UMC "}, + {nzProcessorVendor_VIA, "VIA VIA VIA "}, + {nzProcessorVendor_VIA, "Vortex86 SoC"} + }; + + // Identification du vendeur + s_vendorEnum = nzProcessorVendor_Unknown; + for (const VendorString& vendorString : s_vendorStrings) + { + if (std::memcmp(s_vendor, vendorString.vendor, 12) == 0) + { + s_vendorEnum = vendorString.vendorEnum; + break; + } + } + + unsigned int ids = result[0]; + + if (ids >= 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; + } + + NzHardwareInfoImpl::Cpuid(0x80000000, result); + unsigned int exIds = result[0]; + + if (exIds >= 0x80000001) + { + NzHardwareInfoImpl::Cpuid(0x80000001, result); + 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; + s_x64 = (result[3] & (1U << 29)) != 0; + } + + return true; +} + +bool NzHardwareInfo::Is64Bits() +{ + return s_x64; +} + +void NzHardwareInfo::Uninitialize() +{ + // Rien à faire +} diff --git a/src/Nazara/Core/Win32/HardwareInfoImpl.cpp b/src/Nazara/Core/Win32/HardwareInfoImpl.cpp new file mode 100644 index 000000000..089168d31 --- /dev/null +++ b/src/Nazara/Core/Win32/HardwareInfoImpl.cpp @@ -0,0 +1,82 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine - Core module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +#ifdef NAZARA_COMPILER_MSVC +#include +#endif + +#include + +void NzHardwareInfoImpl::Cpuid(nzUInt32 code, nzUInt32 result[4]) +{ + #if defined(NAZARA_COMPILER_MSVC) + __cpuid(reinterpret_cast(result), static_cast(code)); + #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" + :"=a" (result[0]), "=b" (result[1]), "=c" (result[2]), "=d" (result[3]) + :"a" (code), "c" (0)); + #else + NazaraInternalError("Cpuid has been called although it is not supported"); + #endif +} + +unsigned int NzHardwareInfoImpl::GetProcessorCount() +{ + // Plus simple (et plus portable) que de passer par le CPUID + SYSTEM_INFO infos; + GetSystemInfo(&infos); + + return infos.dwNumberOfProcessors; +} + +bool NzHardwareInfoImpl::IsCpuidSupported() +{ + #if defined(NAZARA_COMPILER_MSVC) + int supported; + __asm + { + pushfd + pop eax + mov ecx, eax + xor eax, 0x200000 + push eax + popfd + pushfd + pop eax + xor eax, ecx + mov supported, eax + push ecx + popfd + }; + + return supported != 0; + #elif defined(NAZARA_COMPILER_CLANG) || defined(NAZARA_COMPILER_GCC) || defined(NAZARA_COMPILER_INTEL) + int supported; + asm volatile + (" pushfl\n" + " pop %%eax\n" + " mov %%eax, %%ecx\n" + " xor $0x200000, %%eax\n" + " push %%eax\n" + " popfl\n" + " pushfl\n" + " pop %%eax\n" + " xor %%ecx, %%eax\n" + " mov %%eax, %0\n" + " push %%ecx\n" + " popfl\n" + : "=m" (supported) + : :"eax", "ecx", "memory"); + + return supported != 0; + #else + return false; + #endif +} diff --git a/src/Nazara/Core/Win32/HardwareInfoImpl.hpp b/src/Nazara/Core/Win32/HardwareInfoImpl.hpp new file mode 100644 index 000000000..aa7c95574 --- /dev/null +++ b/src/Nazara/Core/Win32/HardwareInfoImpl.hpp @@ -0,0 +1,20 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine - Core module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_HARDWAREINFOIMPL_WINDOWS_HPP +#define NAZARA_HARDWAREINFOIMPL_WINDOWS_HPP + +#include + +class NzHardwareInfoImpl +{ + public: + static void Cpuid(unsigned int code, nzUInt32 result[4]); + static unsigned int GetProcessorCount(); + static bool IsCpuidSupported(); +}; + +#endif // NAZARA_HARDWAREINFOIMPL_WINDOWS_HPP