ppsspp/Common/ArmCPUDetect.cpp
Henrik Rydgård ff8148dd92 Move native/util, native/data and native/i18 to Common/Data.
Also move colorutil.cpp/h

linking build fix experiment

Delete a bunch of unused CMakeLists.txt files

CMakeLists.txt linking fix

Don't include NativeApp.h from any headers.

Android.mk buildfix

Half of the UWP fix

Buildfix

Minor project file cleanup

Buildfixes

Guess what? More buildfixes!
2020-10-04 07:28:29 +02:00

335 lines
7.9 KiB
C++

// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "ppsspp_config.h"
#include <sstream>
#if PPSSPP_ARCH(ARM) || PPSSPP_ARCH(ARM64)
#include <ctype.h>
#include "Common.h"
#include "CPUDetect.h"
#include "StringUtils.h"
#include "FileUtil.h"
#include "Common/Data/Encoding/Utf8.h"
#if PPSSPP_PLATFORM(WINDOWS)
#if PPSSPP_PLATFORM(UWP)
// TODO: Maybe we can move the implementation here?
std::string GetCPUBrandString();
#else
// No CPUID on ARM, so we'll have to read the registry
#include <windows.h>
std::string GetCPUBrandString() {
std::string cpu_string;
HKEY key;
LSTATUS result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, KEY_READ, &key);
if (result == ERROR_SUCCESS) {
DWORD size = 0;
DWORD type = REG_SZ;
RegQueryValueEx(key, L"ProcessorNameString", NULL, &type, NULL, &size);
LPBYTE buff = (LPBYTE)malloc(size);
if (buff != NULL) {
RegQueryValueEx(key, L"ProcessorNameString", NULL, &type, buff, &size);
cpu_string = ConvertWStringToUTF8((wchar_t*)buff);
free(buff);
}
RegCloseKey(key);
}
if (cpu_string.empty())
return "Unknown";
else
return cpu_string;
}
#endif
#endif
// Only Linux platforms have /proc/cpuinfo
#if PPSSPP_PLATFORM(LINUX)
const char procfile[] = "/proc/cpuinfo";
// https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-devices-system-cpu
const char syscpupresentfile[] = "/sys/devices/system/cpu/present";
std::string GetCPUString() {
std::string cpu_string;
std::fstream file;
if (File::OpenCPPFile(file, procfile, std::ios::in)) {
std::string line, marker = "Hardware\t: ";
while (std::getline(file, line)) {
if (line.find(marker) != std::string::npos) {
cpu_string = line.substr(marker.length());
}
}
}
if (cpu_string.empty())
cpu_string = "Unknown";
else if (cpu_string.back() == '\n')
cpu_string.pop_back(); // Drop the new-line character
return cpu_string;
}
std::string GetCPUBrandString() {
std::string brand_string;
std::fstream file;
if (File::OpenCPPFile(file, procfile, std::ios::in)) {
std::string line, marker = "Processor\t: ";
while (std::getline(file, line)) {
if (line.find(marker) != std::string::npos) {
brand_string = line.substr(marker.length());
if (brand_string.length() != 0 && !isdigit(brand_string[0])) {
break;
}
}
}
}
if (brand_string.empty())
brand_string = "Unknown";
else if (brand_string.back() == '\n')
brand_string.pop_back(); // Drop the new-line character
return brand_string;
}
unsigned char GetCPUImplementer()
{
std::string line, marker = "CPU implementer\t: ";
unsigned char implementer = 0;
std::fstream file;
if (!File::OpenCPPFile(file, procfile, std::ios::in))
return 0;
while (std::getline(file, line))
{
if (line.find(marker) != std::string::npos)
{
line = line.substr(marker.length());
sscanf(line.c_str(), "0x%02hhx", &implementer);
break;
}
}
return implementer;
}
unsigned short GetCPUPart()
{
std::string line, marker = "CPU part\t: ";
unsigned short part = 0;
std::fstream file;
if (!File::OpenCPPFile(file, procfile, std::ios::in))
return 0;
while (std::getline(file, line))
{
if (line.find(marker) != std::string::npos)
{
line = line.substr(marker.length());
sscanf(line.c_str(), "0x%03hx", &part);
break;
}
}
return part;
}
bool CheckCPUFeature(const std::string& feature)
{
std::string line, marker = "Features\t: ";
std::fstream file;
if (!File::OpenCPPFile(file, procfile, std::ios::in))
return 0;
while (std::getline(file, line))
{
if (line.find(marker) != std::string::npos)
{
std::stringstream line_stream(line);
std::string token;
while (std::getline(line_stream, token, ' '))
{
if (token == feature)
return true;
}
}
}
return false;
}
int GetCoreCount()
{
std::string line, marker = "processor\t: ";
int cores = 1;
std::fstream file;
if (File::OpenCPPFile(file, syscpupresentfile, std::ios::in))
{
int low, high, found;
std::getline(file, line);
found = sscanf(line.c_str(), "%d-%d", &low, &high);
if (found == 1)
return 1;
if (found == 2)
return high - low + 1;
}
if (!File::OpenCPPFile(file, procfile, std::ios::in))
return 1;
while (std::getline(file, line))
{
if (line.find(marker) != std::string::npos)
++cores;
}
return cores;
}
#endif
CPUInfo cpu_info;
CPUInfo::CPUInfo() {
Detect();
}
// Detects the various cpu features
void CPUInfo::Detect()
{
// Set some defaults here
HTT = false;
#if PPSSPP_ARCH(ARM64)
OS64bit = true;
CPU64bit = true;
Mode64bit = true;
#else
OS64bit = false;
CPU64bit = false;
Mode64bit = false;
#endif
vendor = VENDOR_ARM;
// Get the information about the CPU
#if !PPSSPP_PLATFORM(LINUX)
bool isVFP3 = false;
bool isVFP4 = false;
#if PPSSPP_PLATFORM(IOS)
isVFP3 = true;
// Check for swift arch (VFP4)
#ifdef __ARM_ARCH_7S__
isVFP4 = true;
#endif
strcpy(brand_string, "Apple A");
num_cores = 2;
#elif PPSSPP_PLATFORM(WINDOWS)
truncate_cpy(brand_string, GetCPUBrandString().c_str());
isVFP3 = true;
isVFP4 = false;
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
num_cores = sysInfo.dwNumberOfProcessors;
#else // !PPSSPP_PLATFORM(IOS)
strcpy(brand_string, "Unknown");
num_cores = 1;
#endif
truncate_cpy(cpu_string, brand_string);
// Hardcode this for now
bSwp = true;
bHalf = true;
bThumb = false;
bFastMult = true;
bVFP = true;
bEDSP = true;
bThumbEE = isVFP3;
bNEON = isVFP3;
bVFPv3 = isVFP3;
bTLS = true;
bVFPv4 = isVFP4;
bIDIVa = isVFP4;
bIDIVt = isVFP4;
bFP = false;
bASIMD = false;
#else // PPSSPP_PLATFORM(LINUX)
truncate_cpy(cpu_string, GetCPUString().c_str());
truncate_cpy(brand_string, GetCPUBrandString().c_str());
bSwp = CheckCPUFeature("swp");
bHalf = CheckCPUFeature("half");
bThumb = CheckCPUFeature("thumb");
bFastMult = CheckCPUFeature("fastmult");
bVFP = CheckCPUFeature("vfp");
bEDSP = CheckCPUFeature("edsp");
bThumbEE = CheckCPUFeature("thumbee");
bNEON = CheckCPUFeature("neon");
bVFPv3 = CheckCPUFeature("vfpv3");
bTLS = CheckCPUFeature("tls");
bVFPv4 = CheckCPUFeature("vfpv4");
bIDIVa = CheckCPUFeature("idiva");
bIDIVt = CheckCPUFeature("idivt");
// Qualcomm Krait supports IDIVA but it doesn't report it. Check for krait (0x4D = Plus, 0x6F = Pro).
unsigned short CPUPart = GetCPUPart();
if (GetCPUImplementer() == 0x51 && (CPUPart == 0x4D || CPUPart == 0x6F))
bIDIVa = bIDIVt = true;
// These two require ARMv8 or higher
bFP = CheckCPUFeature("fp");
bASIMD = CheckCPUFeature("asimd");
num_cores = GetCoreCount();
#endif
#if PPSSPP_ARCH(ARM64)
// Whether the above detection failed or not, on ARM64 we do have ASIMD/NEON.
bNEON = true;
bASIMD = true;
#endif
}
// Turn the cpu info into a string we can show
std::string CPUInfo::Summarize()
{
std::string sum;
if (num_cores == 1)
sum = StringFromFormat("%s, %d core", cpu_string, num_cores);
else
sum = StringFromFormat("%s, %d cores", cpu_string, num_cores);
if (bSwp) sum += ", SWP";
if (bHalf) sum += ", Half";
if (bThumb) sum += ", Thumb";
if (bFastMult) sum += ", FastMult";
if (bEDSP) sum += ", EDSP";
if (bThumbEE) sum += ", ThumbEE";
if (bTLS) sum += ", TLS";
if (bVFP) sum += ", VFP";
if (bVFPv3) sum += ", VFPv3";
if (bVFPv4) sum += ", VFPv4";
if (bNEON) sum += ", NEON";
if (bIDIVa) sum += ", IDIVa";
if (bIDIVt) sum += ", IDIVt";
if (CPU64bit) sum += ", 64-bit";
return sum;
}
#endif // PPSSPP_ARCH(ARM) || PPSSPP_ARCH(ARM64)