Common: Add CPU feature detection for ARM64
This commit is contained in:
parent
f1c2f63aa1
commit
0af8406e44
|
@ -125,6 +125,12 @@ if(ARCHITECTURE_x86_64)
|
||||||
x64/xbyak_abi.h
|
x64/xbyak_abi.h
|
||||||
x64/xbyak_util.h
|
x64/xbyak_util.h
|
||||||
)
|
)
|
||||||
|
elseif(ARCHITECTURE_ARM64)
|
||||||
|
target_sources(common
|
||||||
|
PRIVATE
|
||||||
|
aarch64/cpu_detect.cpp
|
||||||
|
aarch64/cpu_detect.h
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
create_target_directory_groups(common)
|
create_target_directory_groups(common)
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
// Copyright 2013 Dolphin Emulator Project / 2022 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <fstream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
// clang-format off
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
// clang-format on
|
||||||
|
#elif !defined(_WIN32)
|
||||||
|
#ifndef __FreeBSD__
|
||||||
|
#include <asm/hwcap.h>
|
||||||
|
#endif // __FreeBSD__
|
||||||
|
#include <sys/auxv.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif // __APPLE__
|
||||||
|
|
||||||
|
#include "common/aarch64/cpu_detect.h"
|
||||||
|
#include "common/file_util.h"
|
||||||
|
|
||||||
|
namespace Common {
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
static std::string GetCPUString() {
|
||||||
|
char buf[128];
|
||||||
|
size_t buf_len = sizeof(buf);
|
||||||
|
if (sysctlbyname("machdep.cpu.brand_string", &buf, &buf_len, NULL, 0) == -1) {
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
#elif !defined(WIN32)
|
||||||
|
static std::string GetCPUString() {
|
||||||
|
constexpr char procfile[] = "/proc/cpuinfo";
|
||||||
|
constexpr char marker[] = "Hardware\t: ";
|
||||||
|
std::string cpu_string = "Unknown";
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
std::ifstream file;
|
||||||
|
OpenFStream(file, procfile, std::ios_base::in);
|
||||||
|
|
||||||
|
if (!file)
|
||||||
|
return cpu_string;
|
||||||
|
|
||||||
|
while (std::getline(file, line)) {
|
||||||
|
if (line.find(marker) != std::string::npos) {
|
||||||
|
cpu_string = line.substr(strlen(marker));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cpu_string;
|
||||||
|
}
|
||||||
|
#endif // __APPLE__
|
||||||
|
|
||||||
|
// Detects the various CPU features
|
||||||
|
static CPUCaps Detect() {
|
||||||
|
CPUCaps caps;
|
||||||
|
// Set some defaults here
|
||||||
|
caps.fma = true;
|
||||||
|
caps.afp = false;
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
// M-series CPUs have all of these
|
||||||
|
caps.fp = true;
|
||||||
|
caps.asimd = true;
|
||||||
|
caps.aes = true;
|
||||||
|
caps.crc32 = true;
|
||||||
|
caps.sha1 = true;
|
||||||
|
caps.sha2 = true;
|
||||||
|
caps.cpu_string = GetCPUString();
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
// Windows does not provide any mechanism for querying the system registers on ARMv8, unlike
|
||||||
|
// Linux which traps the register reads and emulates them in the kernel. There are environment
|
||||||
|
// variables containing some of the CPU-specific values, which we could use for a lookup table
|
||||||
|
// in the future. For now, assume all features are present as all known devices which are
|
||||||
|
// Windows-on-ARM compatible also support these extensions.
|
||||||
|
caps.fp = true;
|
||||||
|
caps.asimd = true;
|
||||||
|
caps.aes = true;
|
||||||
|
caps.crc32 = true;
|
||||||
|
caps.sha1 = true;
|
||||||
|
caps.sha2 = true;
|
||||||
|
#else
|
||||||
|
caps.cpu_string = GetCPUString();
|
||||||
|
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
u_long hwcaps = 0;
|
||||||
|
elf_aux_info(AT_HWCAP, &hwcaps, sizeof(u_long));
|
||||||
|
#else
|
||||||
|
unsigned long hwcaps = getauxval(AT_HWCAP);
|
||||||
|
#endif // __FreeBSD__
|
||||||
|
caps.fp = hwcaps & HWCAP_FP;
|
||||||
|
caps.asimd = hwcaps & HWCAP_ASIMD;
|
||||||
|
caps.aes = hwcaps & HWCAP_AES;
|
||||||
|
caps.crc32 = hwcaps & HWCAP_CRC32;
|
||||||
|
caps.sha1 = hwcaps & HWCAP_SHA1;
|
||||||
|
caps.sha2 = hwcaps & HWCAP_SHA2;
|
||||||
|
#endif // __APPLE__
|
||||||
|
return caps;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CPUCaps& GetCPUCaps() {
|
||||||
|
static CPUCaps caps = Detect();
|
||||||
|
return caps;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Common
|
|
@ -0,0 +1,31 @@
|
||||||
|
// Copyright 2013 Dolphin Emulator Project / 2021 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Common {
|
||||||
|
|
||||||
|
/// Arm64 CPU capabilities that may be detected by this module
|
||||||
|
struct CPUCaps {
|
||||||
|
std::string cpu_string;
|
||||||
|
|
||||||
|
bool aes;
|
||||||
|
bool afp; // Alternate floating-point behavior
|
||||||
|
bool asimd;
|
||||||
|
bool crc32;
|
||||||
|
bool fma;
|
||||||
|
bool fp;
|
||||||
|
bool sha1;
|
||||||
|
bool sha2;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the supported capabilities of the host CPU
|
||||||
|
* @return Reference to a CPUCaps struct with the detected host CPU capabilities
|
||||||
|
*/
|
||||||
|
const CPUCaps& GetCPUCaps();
|
||||||
|
|
||||||
|
} // namespace Common
|
Reference in New Issue