From 1049ac23b68784e42a335b8424ed1ef8afd54f55 Mon Sep 17 00:00:00 2001 From: Paul Walker Date: Mon, 3 May 2021 12:32:51 -0400 Subject: [PATCH] CPU Info Shenanigans 1. Add the google C++ cpu detection protable code as a submod 2. Turn on AVX flags at build time 3. If you are running on a non-AVX box pop a warning saying may not work in the future 4. get popcorn Closes #4466 --- .gitmodules | 3 ++ CMakeLists.txt | 21 ++++++++- libs/cpu_features | 1 + src/common/CPUFeatures.cpp | 83 +++++++++++++++++++++++++++++++++ src/common/CPUFeatures.h | 33 +++++++++++++ src/common/SurgeSynthesizer.cpp | 10 ++++ src/gui/CAboutBox.cpp | 63 +------------------------ 7 files changed, 152 insertions(+), 62 deletions(-) create mode 160000 libs/cpu_features create mode 100644 src/common/CPUFeatures.cpp create mode 100644 src/common/CPUFeatures.h diff --git a/.gitmodules b/.gitmodules index 59eaf4583f3..2001bc904f0 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,3 +22,6 @@ [submodule "libs/JUCE"] path = libs/JUCE url = https://github.com/juce-framework/JUCE +[submodule "libs/cpu_features"] + path = libs/cpu_features + url = https://github.com/google/cpu_features.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 5832cf4bef6..726a937d73f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,21 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") add_compile_options(-msse2 -mfpmath=sse) endif() endif() + + # Add AVX support + include(CheckCXXSourceCompiles) + check_cxx_source_compiles(" +#if defined(__x86_64__) || defined(__SSE2__) || defined(_M_AMD64) || defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2) + #ifndef __AVX__ + #error + #endif +#endif + int main() {}" COMPILER_HAS_AVX_OR_IS_ARM) + if (NOT COMPILER_HAS_AVX_OR_IS_ARM) + message(STATUS "Adding -mavx to allow __AVX__ compiles" ) + add_compile_options("-mavx") + endif() + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") # Any Clang add_compile_options( @@ -76,7 +91,6 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") endif() if(MSVC) - # MSVC and pretenders add_compile_options( -WX # treat all warnings as errors @@ -97,6 +111,8 @@ if(MSVC) /Zc:alignedNew /bigobj + /arch:AVX + # Build with Multiple Processes (Clang-cl builds use Ninja instead) $<$:/MP> ) @@ -138,6 +154,7 @@ add_subdirectory(libs/escape-from-vstgui) add_subdirectory(libs/oddsound-mts) add_subdirectory(libs/libsamplerate EXCLUDE_FROM_ALL) add_subdirectory(libs/sqlite-3.23.3) +add_subdirectory(libs/cpu_features EXCLODE_FROM_ALL) juce_add_binary_data(surge-shared-binary NAMESPACE SurgeCoreBinary @@ -159,6 +176,7 @@ target_link_libraries(surge-shared PUBLIC surge::oddsound-mts samplerate surge-shared-binary + cpu_features ) # We want to run this once alas, since JUCE needs it even though it is a byproduct of a phase to build the @@ -274,6 +292,7 @@ set(SURGE_SHARED_SOURCES src/common/vt_dsp/halfratefilter.cpp src/common/vt_dsp/lipol.cpp src/common/vt_dsp/macspecific.cpp + src/common/CPUFeatures.cpp src/common/DebugHelpers.cpp src/common/ModulatorPresetManager.cpp src/common/Parameter.cpp diff --git a/libs/cpu_features b/libs/cpu_features new file mode 160000 index 00000000000..3e8243b7d99 --- /dev/null +++ b/libs/cpu_features @@ -0,0 +1 @@ +Subproject commit 3e8243b7d9951c078259c3186c039a6e8f036055 diff --git a/src/common/CPUFeatures.cpp b/src/common/CPUFeatures.cpp new file mode 100644 index 00000000000..97a5c230e55 --- /dev/null +++ b/src/common/CPUFeatures.cpp @@ -0,0 +1,83 @@ +/* +** Surge Synthesizer is Free and Open Source Software +** +** Surge is made available under the Gnu General Public License, v3.0 +** https://www.gnu.org/licenses/gpl-3.0.en.html +** +** Copyright 2004-2021 by various individuals as described by the Git transaction log +** +** All source at: https://github.com/surge-synthesizer/surge.git +** +** Surge was a commercial product from 2004-2018, with Copyright and ownership +** in that period held by Claes Johanson at Vember Audio. Claes made Surge +** open source in September 2018. +*/ + +#include "CPUFeatures.h" +#include "globals.h" + +#if ARM_NEON +#else +#include "cpuinfo_x86.h" +#endif + +using namespace cpu_features; + +namespace Surge +{ +namespace CPUFeatures +{ +#if ARM_NEON +#else +static const X86Features features = GetX86Info().features; +#endif + +std::string cpuBrand() +{ +#if ARM_NEON + return "ARM Processor"; +#else + char bs[49]; + FillX86BrandString(bs); + return bs; +#endif +} + +bool isArm() +{ +#if ARM_NEON + return true; +#else + return false; +#endif +} +bool isX86() +{ +#if ARM_NEON + return false; +#else + return true; +#endif +} +bool hasSSE2() +{ +#if ARM_NEON + return true; // thanks simde +#else + return features.sse2; +#endif +} +bool hasAVX() +{ +#if ARM_NEON + return true; // thanks simde +#else + return features.avx; +#endif +} + +#if !CPU_FEATURES_COMPILED_X86_AVX +#error "You must compile SURGE with AVX support in compiler flags" +#endif +} // namespace CPUFeatures +} // namespace Surge \ No newline at end of file diff --git a/src/common/CPUFeatures.h b/src/common/CPUFeatures.h new file mode 100644 index 00000000000..687d280cbda --- /dev/null +++ b/src/common/CPUFeatures.h @@ -0,0 +1,33 @@ +/* +** Surge Synthesizer is Free and Open Source Software +** +** Surge is made available under the Gnu General Public License, v3.0 +** https://www.gnu.org/licenses/gpl-3.0.en.html +** +** Copyright 2004-2021 by various individuals as described by the Git transaction log +** +** All source at: https://github.com/surge-synthesizer/surge.git +** +** Surge was a commercial product from 2004-2018, with Copyright and ownership +** in that period held by Claes Johanson at Vember Audio. Claes made Surge +** open source in September 2018. +*/ + +#ifndef SURGE_XT_CPUFEATURES_H +#define SURGE_XT_CPUFEATURES_H + +#include + +namespace Surge +{ +namespace CPUFeatures +{ +std::string cpuBrand(); +bool isArm(); +bool isX86(); +bool hasSSE2(); +bool hasAVX(); +}; // namespace CPUFeatures +} // namespace Surge + +#endif // SURGE_XT_CPUFEATURES_H diff --git a/src/common/SurgeSynthesizer.cpp b/src/common/SurgeSynthesizer.cpp index 3c3a4db9302..83623c7c7b3 100644 --- a/src/common/SurgeSynthesizer.cpp +++ b/src/common/SurgeSynthesizer.cpp @@ -16,6 +16,7 @@ #include "SurgeSynthesizer.h" #include "DspUtilities.h" #include +#include "CPUFeatures.h" #if MAC || LINUX #include #else @@ -38,6 +39,15 @@ SurgeSynthesizer::SurgeSynthesizer(PluginLayer *parent, std::string suppliedData : storage(suppliedDataPath), hpA(&storage), hpB(&storage), _parent(parent), halfbandA(6, true), halfbandB(6, true), halfbandIN(6, true) { + // Remember CPU features works on ARM also + if (!Surge::CPUFeatures::hasAVX()) + { + storage.reportError("Surge XT in the future will require processor with AVX extensions. Surge Xt may" + " not work on this hardware in future versions. Enjoy Surge 1.9!", + "CPU Incompatability"); + // Try anyway + } + switch_toggled_queued = false; audio_processing_active = false; halt_engine = false; diff --git a/src/gui/CAboutBox.cpp b/src/gui/CAboutBox.cpp index debb51d921c..fa626ada080 100644 --- a/src/gui/CAboutBox.cpp +++ b/src/gui/CAboutBox.cpp @@ -10,6 +10,7 @@ #include "SurgeGUIEditor.h" #include "CScalableBitmap.h" #include "CTextButtonWithHover.h" +#include "CPUFeatures.h" #if WINDOWS // For __cpuid so we can get processor name @@ -189,73 +190,13 @@ CAboutBox::CAboutBox(const CRect &size, SurgeGUIEditor *editor, SurgeStorage *st std::string flavor = wrapperType; - std::string arch = std::string(Surge::Build::BuildArch); + std::string arch = Surge::CPUFeatures::cpuBrand(); #if MAC std::string platform = "macOS"; - - char buffer[1024]; - size_t bufsz = sizeof(buffer); - if (sysctlbyname("machdep.cpu.brand_string", (void *)(&buffer), &bufsz, nullptr, (size_t)0) < 0) - { -#if ARM_NEON - arch = "Apple Silicon"; -#endif - } - else - { - arch = buffer; -#if ARM_NEON - arch += " (Apple Silicon)"; -#endif - } - #elif WINDOWS std::string platform = "Windows"; - - int CPUInfo[4] = {-1}; - unsigned nExIds, i = 0; - char CPUBrandString[0x40]; - // Get the information associated with each extended ID. - __cpuid(CPUInfo, 0x80000000); - nExIds = CPUInfo[0]; - for (i = 0x80000000; i <= nExIds; ++i) - { - __cpuid(CPUInfo, i); - // Interpret CPU brand string - if (i == 0x80000002) - memcpy(CPUBrandString, CPUInfo, sizeof(CPUInfo)); - else if (i == 0x80000003) - memcpy(CPUBrandString + 16, CPUInfo, sizeof(CPUInfo)); - else if (i == 0x80000004) - memcpy(CPUBrandString + 32, CPUInfo, sizeof(CPUInfo)); - } - arch = CPUBrandString; #elif LINUX std::string platform = "Linux"; - - // Lets see what /proc/cpuinfo has to say for us - // on intels this is "model name" - auto pinfo = std::ifstream("/proc/cpuinfo"); - if (pinfo.is_open()) - { - std::string line; - while (std::getline(pinfo, line)) - { - if (line.find("model name") == 0) - { - auto colon = line.find(":"); - arch = line.substr(colon + 1); - break; - } - if (line.find("Model") == 0) // rasperry pi branch - { - auto colon = line.find(":"); - arch = line.substr(colon + 1); - break; - } - } - } - pinfo.close(); #else std::string platform = "GLaDOS, Orac or Skynet"; #endif