mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Windows: Added Windows ARM support to JUCE
This commit is contained in:
parent
5f48ca7269
commit
2d42b9a44f
8 changed files with 189 additions and 93 deletions
|
|
@ -1430,34 +1430,44 @@ void JUCE_CALLTYPE FloatVectorOperations::convertFixedToFloat (float* dest, cons
|
|||
intptr_t JUCE_CALLTYPE FloatVectorOperations::getFpStatusRegister() noexcept
|
||||
{
|
||||
intptr_t fpsr = 0;
|
||||
#if JUCE_INTEL && JUCE_USE_SSE_INTRINSICS
|
||||
#if JUCE_INTEL && JUCE_USE_SSE_INTRINSICS
|
||||
fpsr = static_cast<intptr_t> (_mm_getcsr());
|
||||
#elif defined(__arm64__) || defined(__aarch64__) || JUCE_USE_ARM_NEON
|
||||
#if defined(__arm64__) || defined(__aarch64__)
|
||||
#elif (JUCE_64BIT && JUCE_ARM) || JUCE_USE_ARM_NEON
|
||||
#if _MSC_VER
|
||||
// _control87 returns static values for x86 bits that don't exist on arm
|
||||
// to emulate x86 behaviour. We are only ever interested in de-normal bits
|
||||
// so mask out only those.
|
||||
fpsr = (intptr_t) (_control87 (0, 0) & _MCW_DN);
|
||||
#else
|
||||
#if JUCE_64BIT
|
||||
asm volatile("mrs %0, fpcr"
|
||||
: "=r"(fpsr));
|
||||
#elif JUCE_USE_ARM_NEON
|
||||
asm volatile("vmrs %0, fpscr"
|
||||
: "=r"(fpsr));
|
||||
#endif
|
||||
#else
|
||||
#if ! (defined(JUCE_INTEL) || defined(JUCE_ARM))
|
||||
jassertfalse; // No support for getting the floating point status register for your platform
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#if ! (defined (JUCE_INTEL) || defined (JUCE_ARM))
|
||||
jassertfalse; // No support for getting the floating point status register for your platform
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return fpsr;
|
||||
}
|
||||
|
||||
void JUCE_CALLTYPE FloatVectorOperations::setFpStatusRegister (intptr_t fpsr) noexcept
|
||||
{
|
||||
#if JUCE_INTEL && JUCE_USE_SSE_INTRINSICS
|
||||
#if JUCE_INTEL && JUCE_USE_SSE_INTRINSICS
|
||||
// the volatile keyword here is needed to workaround a bug in AppleClang 13.0
|
||||
// which aggressively optimises away the variable otherwise
|
||||
volatile auto fpsr_w = static_cast<uint32_t> (fpsr);
|
||||
_mm_setcsr (fpsr_w);
|
||||
#elif defined(__arm64__) || defined(__aarch64__) || JUCE_USE_ARM_NEON
|
||||
#if defined(__arm64__) || defined(__aarch64__)
|
||||
#elif (JUCE_64BIT && JUCE_ARM) || JUCE_USE_ARM_NEON
|
||||
#if _MSC_VER
|
||||
_control87 ((unsigned int) fpsr, _MCW_DN);
|
||||
#else
|
||||
#if JUCE_64BIT
|
||||
asm volatile("msr fpcr, %0"
|
||||
:
|
||||
: "ri"(fpsr));
|
||||
|
|
@ -1466,17 +1476,18 @@ void JUCE_CALLTYPE FloatVectorOperations::setFpStatusRegister (intptr_t fpsr) no
|
|||
:
|
||||
: "ri"(fpsr));
|
||||
#endif
|
||||
#else
|
||||
#if ! (defined(JUCE_INTEL) || defined(JUCE_ARM))
|
||||
jassertfalse; // No support for getting the floating point status register for your platform
|
||||
#endif
|
||||
ignoreUnused (fpsr);
|
||||
#endif
|
||||
#else
|
||||
#if ! (defined (JUCE_INTEL) || defined (JUCE_ARM))
|
||||
jassertfalse; // No support for getting the floating point status register for your platform
|
||||
#endif
|
||||
ignoreUnused (fpsr);
|
||||
#endif
|
||||
}
|
||||
|
||||
void JUCE_CALLTYPE FloatVectorOperations::enableFlushToZeroMode (bool shouldEnable) noexcept
|
||||
{
|
||||
#if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || defined(__arm64__) || defined(__aarch64__))
|
||||
#if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || (JUCE_64BIT && JUCE_ARM))
|
||||
#if JUCE_USE_SSE_INTRINSICS
|
||||
intptr_t mask = _MM_FLUSH_ZERO_MASK;
|
||||
#else /*JUCE_USE_ARM_NEON*/
|
||||
|
|
@ -1484,7 +1495,7 @@ void JUCE_CALLTYPE FloatVectorOperations::enableFlushToZeroMode (bool shouldEnab
|
|||
#endif
|
||||
setFpStatusRegister ((getFpStatusRegister() & (~mask)) | (shouldEnable ? mask : 0));
|
||||
#else
|
||||
#if ! (defined(JUCE_INTEL) || defined(JUCE_ARM))
|
||||
#if ! (defined (JUCE_INTEL) || defined (JUCE_ARM))
|
||||
jassertfalse; // No support for flush to zero mode on your platform
|
||||
#endif
|
||||
ignoreUnused (shouldEnable);
|
||||
|
|
@ -1493,7 +1504,7 @@ void JUCE_CALLTYPE FloatVectorOperations::enableFlushToZeroMode (bool shouldEnab
|
|||
|
||||
void JUCE_CALLTYPE FloatVectorOperations::disableDenormalisedNumberSupport (bool shouldDisable) noexcept
|
||||
{
|
||||
#if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || defined(__arm64__) || defined(__aarch64__))
|
||||
#if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || (JUCE_64BIT && JUCE_ARM))
|
||||
#if JUCE_USE_SSE_INTRINSICS
|
||||
intptr_t mask = 0x8040;
|
||||
#else /*JUCE_USE_ARM_NEON*/
|
||||
|
|
@ -1504,7 +1515,7 @@ void JUCE_CALLTYPE FloatVectorOperations::disableDenormalisedNumberSupport (bool
|
|||
#else
|
||||
ignoreUnused (shouldDisable);
|
||||
|
||||
#if ! (defined(JUCE_INTEL) || defined(JUCE_ARM))
|
||||
#if ! (defined (JUCE_INTEL) || defined (JUCE_ARM))
|
||||
jassertfalse; // No support for disable denormals mode on your platform
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -1512,7 +1523,7 @@ void JUCE_CALLTYPE FloatVectorOperations::disableDenormalisedNumberSupport (bool
|
|||
|
||||
bool JUCE_CALLTYPE FloatVectorOperations::areDenormalsDisabled() noexcept
|
||||
{
|
||||
#if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || defined(__arm64__) || defined(__aarch64__))
|
||||
#if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || (JUCE_64BIT && JUCE_ARM))
|
||||
#if JUCE_USE_SSE_INTRINSICS
|
||||
intptr_t mask = 0x8040;
|
||||
#else /*JUCE_USE_ARM_NEON*/
|
||||
|
|
@ -1527,7 +1538,7 @@ bool JUCE_CALLTYPE FloatVectorOperations::areDenormalsDisabled() noexcept
|
|||
|
||||
ScopedNoDenormals::ScopedNoDenormals() noexcept
|
||||
{
|
||||
#if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || defined(__arm64__) || defined(__aarch64__))
|
||||
#if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || (JUCE_64BIT && JUCE_ARM))
|
||||
#if JUCE_USE_SSE_INTRINSICS
|
||||
intptr_t mask = 0x8040;
|
||||
#else /*JUCE_USE_ARM_NEON*/
|
||||
|
|
@ -1541,7 +1552,7 @@ ScopedNoDenormals::ScopedNoDenormals() noexcept
|
|||
|
||||
ScopedNoDenormals::~ScopedNoDenormals() noexcept
|
||||
{
|
||||
#if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || defined(__arm64__) || defined(__aarch64__))
|
||||
#if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || (JUCE_64BIT && JUCE_ARM))
|
||||
FloatVectorOperations::setFpStatusRegister (fpsr);
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -261,7 +261,7 @@ public:
|
|||
~ScopedNoDenormals() noexcept;
|
||||
|
||||
private:
|
||||
#if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || defined (__arm64__) || defined (__aarch64__))
|
||||
#if JUCE_USE_SSE_INTRINSICS || (JUCE_USE_ARM_NEON || (JUCE_64BIT && JUCE_ARM))
|
||||
intptr_t fpsr;
|
||||
#endif
|
||||
};
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ static inline int vorbis_ftoi(double f){ /* yes, double! Otherwise,
|
|||
|
||||
/* MSVC inline assembly. 32 bit only; inline ASM isn't implemented in the
|
||||
* 64 bit compiler and doesn't work on arm. */
|
||||
#if defined(_MSC_VER) && defined(_M_IX86) && !defined(_WIN32_WCE)
|
||||
#if (defined(_MSC_VER) && defined(_M_IX86) && !defined(_WIN32_WCE)) && (! JUCE_ARM)
|
||||
# define VORBIS_FPU_CONTROL
|
||||
|
||||
typedef ogg_int16_t vorbis_fpu_control;
|
||||
|
|
@ -146,7 +146,7 @@ static __inline void vorbis_fpu_restore(vorbis_fpu_control fpu){
|
|||
|
||||
/* Optimized code path for x86_64 builds. Uses SSE2 intrinsics. This can be
|
||||
done safely because all x86_64 CPUs supports SSE2. */
|
||||
#if ((JUCE_MSVC && JUCE_64BIT) || (JUCE_GCC && defined (__x86_64__)))
|
||||
#if (((JUCE_MSVC && JUCE_64BIT) || (JUCE_GCC && defined (__x86_64__)))) && (! JUCE_ARM)
|
||||
# define VORBIS_FPU_CONTROL
|
||||
|
||||
typedef ogg_int16_t vorbis_fpu_control;
|
||||
|
|
|
|||
|
|
@ -23,11 +23,6 @@
|
|||
namespace juce
|
||||
{
|
||||
|
||||
#if JUCE_MSVC && ! defined (__INTEL_COMPILER)
|
||||
#pragma intrinsic (__cpuid)
|
||||
#pragma intrinsic (__rdtsc)
|
||||
#endif
|
||||
|
||||
void Logger::outputDebugString (const String& text)
|
||||
{
|
||||
OutputDebugString ((text + "\n").toWideCharPointer());
|
||||
|
|
@ -39,9 +34,50 @@ void Logger::outputDebugString (const String& text)
|
|||
JUCE_API void juceDLL_free (void* block) { std::free (block); }
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
static int findNumberOfPhysicalCores() noexcept
|
||||
{
|
||||
#if JUCE_MINGW
|
||||
// Not implemented in MinGW
|
||||
jassertfalse;
|
||||
|
||||
#if JUCE_MINGW || JUCE_CLANG
|
||||
return 1;
|
||||
#else
|
||||
|
||||
DWORD bufferSize = 0;
|
||||
GetLogicalProcessorInformation (nullptr, &bufferSize);
|
||||
|
||||
const auto numBuffers = (size_t) (bufferSize / sizeof (SYSTEM_LOGICAL_PROCESSOR_INFORMATION));
|
||||
|
||||
if (numBuffers == 0)
|
||||
{
|
||||
jassertfalse;
|
||||
return 0;
|
||||
};
|
||||
|
||||
HeapBlock<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> buffer (numBuffers);
|
||||
|
||||
if (! GetLogicalProcessorInformation (buffer, &bufferSize))
|
||||
{
|
||||
jassertfalse;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (int) std::count_if (buffer.get(), buffer.get() + numBuffers, [] (const auto& info)
|
||||
{
|
||||
return info.Relationship == RelationProcessorCore;
|
||||
});
|
||||
|
||||
#endif // JUCE_MINGW
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_INTEL
|
||||
#if JUCE_MSVC && ! defined (__INTEL_COMPILER)
|
||||
#pragma intrinsic (__cpuid)
|
||||
#pragma intrinsic (__rdtsc)
|
||||
#endif
|
||||
|
||||
#if JUCE_MINGW || JUCE_CLANG
|
||||
static void callCPUID (int result[4], uint32 type)
|
||||
{
|
||||
uint32 la = (uint32) result[0], lb = (uint32) result[1],
|
||||
|
|
@ -59,12 +95,12 @@ static void callCPUID (int result[4], uint32 type)
|
|||
result[0] = (int) la; result[1] = (int) lb;
|
||||
result[2] = (int) lc; result[3] = (int) ld;
|
||||
}
|
||||
#else
|
||||
#else
|
||||
static void callCPUID (int result[4], int infoType)
|
||||
{
|
||||
__cpuid (result, infoType);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
String SystemStats::getCpuVendor()
|
||||
{
|
||||
|
|
@ -103,34 +139,6 @@ String SystemStats::getCpuModel()
|
|||
return String (name).trim();
|
||||
}
|
||||
|
||||
static int findNumberOfPhysicalCores() noexcept
|
||||
{
|
||||
#if JUCE_MINGW
|
||||
// Not implemented in MinGW
|
||||
jassertfalse;
|
||||
|
||||
return 1;
|
||||
#else
|
||||
|
||||
int numPhysicalCores = 0;
|
||||
DWORD bufferSize = 0;
|
||||
GetLogicalProcessorInformation (nullptr, &bufferSize);
|
||||
|
||||
if (auto numBuffers = (size_t) (bufferSize / sizeof (SYSTEM_LOGICAL_PROCESSOR_INFORMATION)))
|
||||
{
|
||||
HeapBlock<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> buffer (numBuffers);
|
||||
|
||||
if (GetLogicalProcessorInformation (buffer, &bufferSize))
|
||||
for (size_t i = 0; i < numBuffers; ++i)
|
||||
if (buffer[i].Relationship == RelationProcessorCore)
|
||||
++numPhysicalCores;
|
||||
}
|
||||
|
||||
return numPhysicalCores;
|
||||
#endif // JUCE_MINGW
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void CPUInformation::initialise() noexcept
|
||||
{
|
||||
int info[4] = { 0 };
|
||||
|
|
@ -176,6 +184,49 @@ void CPUInformation::initialise() noexcept
|
|||
if (numPhysicalCPUs <= 0)
|
||||
numPhysicalCPUs = numLogicalCPUs;
|
||||
}
|
||||
#elif JUCE_ARM
|
||||
String SystemStats::getCpuVendor()
|
||||
{
|
||||
static const auto cpuVendor = []
|
||||
{
|
||||
static constexpr auto* path = "HKEY_LOCAL_MACHINE\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0\\VendorIdentifier";
|
||||
auto vendor = RegistryKeyWrapper::getValue (path, {}, 0).trim();
|
||||
|
||||
return vendor.isEmpty() ? String ("Unknown Vendor") : vendor;
|
||||
}();
|
||||
|
||||
return cpuVendor;
|
||||
}
|
||||
|
||||
String SystemStats::getCpuModel()
|
||||
{
|
||||
static const auto cpuModel = []
|
||||
{
|
||||
static constexpr auto* path = "HKEY_LOCAL_MACHINE\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0\\ProcessorNameString";
|
||||
auto model = RegistryKeyWrapper::getValue (path, {}, 0).trim();
|
||||
|
||||
return model.isEmpty() ? String ("Unknown Model") : model;
|
||||
}();
|
||||
|
||||
return cpuModel;
|
||||
}
|
||||
|
||||
void CPUInformation::initialise() noexcept
|
||||
{
|
||||
// Windows for arm requires at least armv7 which has neon support
|
||||
hasNeon = true;
|
||||
|
||||
SYSTEM_INFO systemInfo;
|
||||
GetNativeSystemInfo (&systemInfo);
|
||||
numLogicalCPUs = (int) systemInfo.dwNumberOfProcessors;
|
||||
numPhysicalCPUs = findNumberOfPhysicalCores();
|
||||
|
||||
if (numPhysicalCPUs <= 0)
|
||||
numPhysicalCPUs = numLogicalCPUs;
|
||||
}
|
||||
#else
|
||||
#error Unknown CPU architecture type
|
||||
#endif
|
||||
|
||||
#if JUCE_MSVC && JUCE_CHECK_MEMORY_LEAKS
|
||||
struct DebugFlagsInitialiser
|
||||
|
|
@ -442,11 +493,21 @@ double Time::getMillisecondCounterHiRes() noexcept { return hiResCounterHa
|
|||
//==============================================================================
|
||||
static int64 juce_getClockCycleCounter() noexcept
|
||||
{
|
||||
#if JUCE_MSVC
|
||||
#if JUCE_MSVC
|
||||
#if JUCE_INTEL
|
||||
// MS intrinsics version...
|
||||
return (int64) __rdtsc();
|
||||
|
||||
#elif JUCE_GCC || JUCE_CLANG
|
||||
#elif JUCE_ARM
|
||||
#if defined (_M_ARM)
|
||||
return __rdpmccntr64();
|
||||
#elif defined (_M_ARM64)
|
||||
return _ReadStatusReg (ARM64_PMCCNTR_EL0);
|
||||
#else
|
||||
#error Unknown arm architecture
|
||||
#endif
|
||||
#endif
|
||||
#elif JUCE_GCC || JUCE_CLANG
|
||||
#if JUCE_INTEL
|
||||
// GNU inline asm version...
|
||||
unsigned int hi = 0, lo = 0;
|
||||
|
||||
|
|
@ -462,9 +523,15 @@ static int64 juce_getClockCycleCounter() noexcept
|
|||
: "cc", "eax", "ebx", "ecx", "edx", "memory");
|
||||
|
||||
return (int64) ((((uint64) hi) << 32) | lo);
|
||||
#else
|
||||
#error "unknown compiler?"
|
||||
#endif
|
||||
#elif JUCE_ARM
|
||||
int64 retval;
|
||||
|
||||
__asm__ __volatile__ ("mrs %0, cntvct_el0" : "=r"(retval));
|
||||
return retval;
|
||||
#endif
|
||||
#else
|
||||
#error "unknown compiler?"
|
||||
#endif
|
||||
}
|
||||
|
||||
int SystemStats::getCpuSpeedInMegahertz()
|
||||
|
|
|
|||
|
|
@ -109,7 +109,11 @@
|
|||
/** If defined, this indicates that the processor is little-endian. */
|
||||
#define JUCE_LITTLE_ENDIAN 1
|
||||
|
||||
#define JUCE_INTEL 1
|
||||
#if defined (_M_ARM) || defined (_M_ARM64) || defined (__arm__) || defined (__aarch64__)
|
||||
#define JUCE_ARM 1
|
||||
#else
|
||||
#define JUCE_INTEL 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
|||
|
|
@ -79,13 +79,13 @@
|
|||
#include "widgets/juce_Chorus.cpp"
|
||||
|
||||
#if JUCE_USE_SIMD
|
||||
#if defined(__i386__) || defined(__amd64__) || defined(_M_X64) || defined(_X86_) || defined(_M_IX86)
|
||||
#if JUCE_INTEL
|
||||
#ifdef __AVX2__
|
||||
#include "native/juce_avx_SIMDNativeOps.cpp"
|
||||
#else
|
||||
#include "native/juce_sse_SIMDNativeOps.cpp"
|
||||
#endif
|
||||
#elif defined(__arm__) || defined(_M_ARM) || defined (__arm64__) || defined (__aarch64__)
|
||||
#elif JUCE_ARM
|
||||
#include "native/juce_neon_SIMDNativeOps.cpp"
|
||||
#else
|
||||
#error "SIMD register support not implemented for this platform"
|
||||
|
|
|
|||
|
|
@ -74,7 +74,9 @@
|
|||
#include <immintrin.h>
|
||||
#endif
|
||||
|
||||
#elif defined (__ARM_NEON__) || defined (__ARM_NEON) || defined (__arm64__) || defined (__aarch64__)
|
||||
// it's ok to check for _M_ARM below as this is only defined on Windows for Arm 32-bit
|
||||
// which has a minimum requirement of armv7, which supports neon.
|
||||
#elif defined (__ARM_NEON__) || defined (__ARM_NEON) || defined (__arm64__) || defined (__aarch64__) || defined (_M_ARM) || defined (_M_ARM64)
|
||||
|
||||
#ifndef JUCE_USE_SIMD
|
||||
#define JUCE_USE_SIMD 1
|
||||
|
|
@ -227,7 +229,7 @@ namespace juce
|
|||
#else
|
||||
#include "native/juce_sse_SIMDNativeOps.h"
|
||||
#endif
|
||||
#elif defined(__arm__) || defined(_M_ARM) || defined (__arm64__) || defined (__aarch64__)
|
||||
#elif JUCE_ARM
|
||||
#include "native/juce_neon_SIMDNativeOps.h"
|
||||
#else
|
||||
#error "SIMD register support not implemented for this platform"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue