diff options
-rw-r--r-- | alc/alc.cpp | 18 | ||||
-rw-r--r-- | alc/cpu_caps.cpp | 197 | ||||
-rw-r--r-- | alc/cpu_caps.h | 12 |
3 files changed, 132 insertions, 95 deletions
diff --git a/alc/alc.cpp b/alc/alc.cpp index 70890186..6ff76d46 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -1090,7 +1090,23 @@ void alc_initconfig(void) } while(next++); } } - FillCPUCaps(capfilter); + if(auto cpuopt = GetCPUInfo()) + { + if(!cpuopt->mVendor.empty() || !cpuopt->mName.empty()) + { + TRACE("Vendor ID: \"%s\"\n", cpuopt->mVendor.c_str()); + TRACE("Name: \"%s\"\n", cpuopt->mName.c_str()); + } + const int caps{cpuopt->mCaps}; + TRACE("Extensions:%s%s%s%s%s%s\n", + ((capfilter&CPU_CAP_SSE) ? ((caps&CPU_CAP_SSE) ? " +SSE" : " -SSE") : ""), + ((capfilter&CPU_CAP_SSE2) ? ((caps&CPU_CAP_SSE2) ? " +SSE2" : " -SSE2") : ""), + ((capfilter&CPU_CAP_SSE3) ? ((caps&CPU_CAP_SSE3) ? " +SSE3" : " -SSE3") : ""), + ((capfilter&CPU_CAP_SSE4_1) ? ((caps&CPU_CAP_SSE4_1) ? " +SSE4.1" : " -SSE4.1") : ""), + ((capfilter&CPU_CAP_NEON) ? ((caps&CPU_CAP_NEON) ? " +NEON" : " -NEON") : ""), + ((!capfilter) ? " -none-" : "")); + CPUCapFlags = caps & capfilter; + } if(auto priopt = ConfigValueInt(nullptr, nullptr, "rt-prio")) RTPrioLevel = *priopt; diff --git a/alc/cpu_caps.cpp b/alc/cpu_caps.cpp index ab6c2d4b..184c23dd 100644 --- a/alc/cpu_caps.cpp +++ b/alc/cpu_caps.cpp @@ -32,145 +32,156 @@ namespace { #if defined(HAVE_GCC_GET_CPUID) \ && (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)) using reg_type = unsigned int; -inline void get_cpuid(unsigned int f, reg_type *regs) -{ __get_cpuid(f, ®s[0], ®s[1], ®s[2], ®s[3]); } +inline std::array<reg_type,4> get_cpuid(unsigned int f) +{ + std::array<reg_type,4> ret{}; + __get_cpuid(f, &ret[0], &ret[1], &ret[2], &ret[3]); + return ret; +} #define CAN_GET_CPUID #elif defined(HAVE_CPUID_INTRINSIC) \ && (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)) using reg_type = int; -inline void get_cpuid(unsigned int f, reg_type *regs) -{ (__cpuid)(regs, f); } +inline std::array<reg_type,4> get_cpuid(unsigned int f) +{ + std::array<reg_type,4> ret{}; + (__cpuid)(ret.data(), f); + return ret; +} #define CAN_GET_CPUID #endif } // namespace - -void FillCPUCaps(int capfilter) +al::optional<CPUInfo> GetCPUInfo() { - int caps{0}; + CPUInfo ret; -/* FIXME: We really should get this for all available CPUs in case different - * CPUs have different caps (is that possible on one machine?). - */ #ifdef CAN_GET_CPUID - union { - reg_type regs[4]; - char str[sizeof(reg_type[4])]; - } cpuinf[3]{}; - - get_cpuid(0, cpuinf[0].regs); - if(cpuinf[0].regs[0] == 0) - ERR("Failed to get CPUID\n"); - else + auto cpuregs = get_cpuid(0); + if(cpuregs[0] == 0) + return al::nullopt; + + const reg_type maxfunc{cpuregs[0]}; + + cpuregs = get_cpuid(0x80000000); + const reg_type maxextfunc{cpuregs[0]}; + + ret.mVendor.append(reinterpret_cast<char*>(&cpuregs[1]), 4); + ret.mVendor.append(reinterpret_cast<char*>(&cpuregs[3]), 4); + ret.mVendor.append(reinterpret_cast<char*>(&cpuregs[2]), 4); + auto iter_end = std::remove(ret.mVendor.begin(), ret.mVendor.end(), '\0'); + while(iter_end != ret.mVendor.begin() && std::isspace(*iter_end)) + --iter_end; + iter_end = std::unique(ret.mVendor.begin(), iter_end, + [](auto&& c0, auto&& c1) { return std::isspace(c0) && std::isspace(c1); }); + ret.mVendor.erase(iter_end, ret.mVendor.end()); + if(!ret.mVendor.empty() && std::isspace(ret.mVendor.front())) + ret.mVendor.erase(ret.mVendor.begin()); + + if(maxextfunc >= 0x80000004) { - const reg_type maxfunc{cpuinf[0].regs[0]}; - - get_cpuid(0x80000000, cpuinf[0].regs); - const reg_type maxextfunc{cpuinf[0].regs[0]}; - - TRACE("Detected max CPUID function: 0x%x (ext. 0x%x)\n", maxfunc, maxextfunc); - - TRACE("Vendor ID: \"%.4s%.4s%.4s\"\n", cpuinf[0].str+4, cpuinf[0].str+12, cpuinf[0].str+8); - if(maxextfunc >= 0x80000004) - { - get_cpuid(0x80000002, cpuinf[0].regs); - get_cpuid(0x80000003, cpuinf[1].regs); - get_cpuid(0x80000004, cpuinf[2].regs); - TRACE("Name: \"%.16s%.16s%.16s\"\n", cpuinf[0].str, cpuinf[1].str, cpuinf[2].str); - } + cpuregs = get_cpuid(0x80000002); + ret.mName.append(reinterpret_cast<char*>(cpuregs.data()), 16); + cpuregs = get_cpuid(0x80000003); + ret.mName.append(reinterpret_cast<char*>(cpuregs.data()), 16); + cpuregs = get_cpuid(0x80000004); + ret.mName.append(reinterpret_cast<char*>(cpuregs.data()), 16); + iter_end = std::remove(ret.mName.begin(), ret.mName.end(), '\0'); + while(iter_end != ret.mName.begin() && std::isspace(*iter_end)) + --iter_end; + iter_end = std::unique(ret.mName.begin(), iter_end, + [](auto&& c0, auto&& c1) { return std::isspace(c0) && std::isspace(c1); }); + ret.mName.erase(iter_end, ret.mName.end()); + if(!ret.mName.empty() && std::isspace(ret.mName.front())) + ret.mName.erase(ret.mName.begin()); + } - if(maxfunc >= 1) - { - get_cpuid(1, cpuinf[0].regs); - if((cpuinf[0].regs[3]&(1<<25))) - caps |= CPU_CAP_SSE; - if((caps&CPU_CAP_SSE) && (cpuinf[0].regs[3]&(1<<26))) - caps |= CPU_CAP_SSE2; - if((caps&CPU_CAP_SSE2) && (cpuinf[0].regs[2]&(1<<0))) - caps |= CPU_CAP_SSE3; - if((caps&CPU_CAP_SSE3) && (cpuinf[0].regs[2]&(1<<19))) - caps |= CPU_CAP_SSE4_1; - } + if(maxfunc >= 1) + { + cpuregs = get_cpuid(1); + if((cpuregs[3]&(1<<25))) + ret.mCaps |= CPU_CAP_SSE; + if((ret.mCaps&CPU_CAP_SSE) && (cpuregs[3]&(1<<26))) + ret.mCaps |= CPU_CAP_SSE2; + if((ret.mCaps&CPU_CAP_SSE2) && (cpuregs[2]&(1<<0))) + ret.mCaps |= CPU_CAP_SSE3; + if((ret.mCaps&CPU_CAP_SSE3) && (cpuregs[2]&(1<<19))) + ret.mCaps |= CPU_CAP_SSE4_1; } + #else + /* Assume support for whatever's supported if we can't check for it */ #if defined(HAVE_SSE4_1) #warning "Assuming SSE 4.1 run-time support!" - caps |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3 | CPU_CAP_SSE4_1; + ret.mCaps |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3 | CPU_CAP_SSE4_1; #elif defined(HAVE_SSE3) #warning "Assuming SSE 3 run-time support!" - caps |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3; + ret.mCaps |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3; #elif defined(HAVE_SSE2) #warning "Assuming SSE 2 run-time support!" - caps |= CPU_CAP_SSE | CPU_CAP_SSE2; + ret.mCaps |= CPU_CAP_SSE | CPU_CAP_SSE2; #elif defined(HAVE_SSE) #warning "Assuming SSE run-time support!" - caps |= CPU_CAP_SSE; -#endif + ret.mCaps |= CPU_CAP_SSE; #endif +#endif /* CAN_GET_CPUID */ #ifdef HAVE_NEON #ifdef __ARM_NEON - caps |= CPU_CAP_NEON; + ret.mCaps |= CPU_CAP_NEON; + #elif defined(_WIN32) && (defined(_M_ARM) || defined(_M_ARM64)) + if(IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE)) - caps |= CPU_CAP_NEON; + ret.mCaps |= CPU_CAP_NEON; + #else + al::ifstream file{"/proc/cpuinfo"}; if(!file.is_open()) - ERR("Failed to open /proc/cpuinfo, cannot check for NEON support\n"); - else + return al::nullopt; + + auto getline = [](std::istream &f, std::string &output) -> bool { - std::string features; + while(f.good() && f.peek() == '\n') + f.ignore(); + return std::getline(f, output) && !output.empty(); + }; + std::string features; + while(getline(file, features)) + { + if(features.compare(0, 10, "Features\t:", 10) == 0) + break; + } + file.close(); - auto getline = [](std::istream &f, std::string &output) -> bool - { - while(f.good() && f.peek() == '\n') - f.ignore(); - return std::getline(f, output) && !output.empty(); - }; - while(getline(file, features)) + size_t extpos{9}; + while((extpos=features.find("neon", extpos+1)) != std::string::npos) + { + if(std::isspace(features[extpos-1]) + && (extpos+4 == features.length() || std::isspace(features[extpos+4]))) { - if(features.compare(0, 10, "Features\t:", 10) == 0) - break; + ret.mCaps |= CPU_CAP_NEON; + break; } - file.close(); - - size_t extpos{9}; - while((extpos=features.find("neon", extpos+1)) != std::string::npos) + } + if(!(ret.mCaps&CPU_CAP_NEON)) + { + extpos = 9; + while((extpos=features.find("asimd", extpos+1)) != std::string::npos) { if(std::isspace(features[extpos-1]) - && (extpos+4 == features.length() || std::isspace(features[extpos+4]))) + && (extpos+5 == features.length() || std::isspace(features[extpos+5]))) { - caps |= CPU_CAP_NEON; + ret.mCaps |= CPU_CAP_NEON; break; } } - if(!(caps&CPU_CAP_NEON)) - { - extpos = 9; - while((extpos=features.find("asimd", extpos+1)) != std::string::npos) - { - if(std::isspace(features[extpos-1]) - && (extpos+5 == features.length() || std::isspace(features[extpos+5]))) - { - caps |= CPU_CAP_NEON; - break; - } - } - } } #endif #endif - TRACE("Extensions:%s%s%s%s%s%s\n", - ((capfilter&CPU_CAP_SSE) ? ((caps&CPU_CAP_SSE) ? " +SSE" : " -SSE") : ""), - ((capfilter&CPU_CAP_SSE2) ? ((caps&CPU_CAP_SSE2) ? " +SSE2" : " -SSE2") : ""), - ((capfilter&CPU_CAP_SSE3) ? ((caps&CPU_CAP_SSE3) ? " +SSE3" : " -SSE3") : ""), - ((capfilter&CPU_CAP_SSE4_1) ? ((caps&CPU_CAP_SSE4_1) ? " +SSE4.1" : " -SSE4.1") : ""), - ((capfilter&CPU_CAP_NEON) ? ((caps&CPU_CAP_NEON) ? " +NEON" : " -NEON") : ""), - ((!capfilter) ? " -none-" : "") - ); - CPUCapFlags = caps & capfilter; + return al::make_optional(ret); } diff --git a/alc/cpu_caps.h b/alc/cpu_caps.h index 64a4ee45..190355b2 100644 --- a/alc/cpu_caps.h +++ b/alc/cpu_caps.h @@ -1,6 +1,10 @@ #ifndef CPU_CAPS_H #define CPU_CAPS_H +#include <string> + +#include "aloptional.h" + extern int CPUCapFlags; enum { @@ -11,6 +15,12 @@ enum { CPU_CAP_NEON = 1<<4, }; -void FillCPUCaps(int capfilter); +struct CPUInfo { + std::string mVendor; + std::string mName; + int mCaps{0}; +}; + +al::optional<CPUInfo> GetCPUInfo(); #endif /* CPU_CAPS_H */ |