Add Windows on ARM64 with MSVC support for Tracy Profiler

Introduce Windows ARM64(native) support across ToyPathTracer,
profiler, and server code paths when building with MSVC(_M_ARM64).

Key changes:
- MathSimd.h/Maths.h:
   - Fix NEON movemask constants for MSVC/ARM64 by loading from a uint32_t[]
    via vld1q_u32() and using vdupq_n_u32() for highbit.
- enkiTS/TaskScheduler.cpp:
   - Provide Pause() implementation on _M_ARM64 using __yield().
- profiler/winmain.cpp:
   -  AVX feature checks to x86/x64 only and skip on ARM64.
- server/TracyPopcnt.hpp:
   - Implement TracyCountBits using ARM NEON intrinsics.
   - Implement TracyLzcnt using _BitScanReverse64().
This commit is contained in:
Naveen Regulla
2026-02-17 16:42:50 +05:30
parent 75320a3353
commit 9879a31fc5
5 changed files with 39 additions and 4 deletions

View File

@@ -8,7 +8,7 @@
#define kSimdWidth 4
#if !defined(__arm__) && !defined(__arm64__) && !defined(__EMSCRIPTEN__)
#if !defined(__arm__) && !defined(__arm64__) && !defined(__EMSCRIPTEN__) && !defined(_M_ARM64)
// ---- SSE implementation
@@ -141,8 +141,14 @@ VM_INLINE float hmin(float4 v)
// Returns a 4-bit code where bit0..bit3 is X..W
VM_INLINE unsigned mask(float4 v)
{
#if defined(_M_ARM64)
static const uint32_t values[4] = { 1u, 2u, 4u, 8u };
const uint32x4_t movemask = vld1q_u32( values );
const uint32x4_t highbit = vdupq_n_u32( 0x80000000u );
#else
static const uint32x4_t movemask = { 1, 2, 4, 8 };
static const uint32x4_t highbit = { 0x80000000, 0x80000000, 0x80000000, 0x80000000 };
#endif
uint32x4_t t0 = vreinterpretq_u32_f32(v.m);
uint32x4_t t1 = vtstq_u32(t0, highbit);
uint32x4_t t2 = vandq_u32(t1, movemask);

View File

@@ -12,7 +12,7 @@
#if DO_FLOAT3_WITH_SIMD
#if !defined(__arm__) && !defined(__arm64__)
#if !defined(__arm__) && !defined(__arm64__) && !defined(_M_ARM64)
// ---- SSE implementation
@@ -223,8 +223,14 @@ VM_INLINE float3 cross(float3 a, float3 b)
// Returns a 3-bit code where bit0..bit2 is X..Z
VM_INLINE unsigned mask(float3 v)
{
#if defined(_M_ARM64)
static const uint32_t values[4] = { 1u, 2u, 4u, 8u };
const uint32x4_t movemask = vld1q_u32( values );
const uint32x4_t highbit = vdupq_n_u32( 0x80000000u );
#else
static const uint32x4_t movemask = { 1, 2, 4, 8 };
static const uint32x4_t highbit = { 0x80000000, 0x80000000, 0x80000000, 0x80000000 };
#endif
uint32x4_t t0 = vreinterpretq_u32_f32(v.m);
uint32x4_t t1 = vtstq_u32(t0, highbit);
uint32x4_t t2 = vandq_u32(t1, movemask);

View File

@@ -72,7 +72,11 @@ namespace
#if defined _M_IX86 || defined _M_X64
#pragma intrinsic(_mm_pause)
inline void Pause() { _mm_pause(); }
#endif
#elif defined(_M_ARM64)
inline void Pause() { __yield(); }
#else
inline void Pause() { /* No ops*/ }
#endif
#elif defined __i386__ || defined __x86_64__
inline void Pause() { __asm__ __volatile__("pause;"); }
#else

View File

@@ -14,6 +14,7 @@ int main( int argc, char** argv );
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmd, int nCmd )
{
#if defined(_M_IX86) || defined(_M_X64)
{
uint32_t regs[4];
__cpuidex( (int*)regs, 0, 0 );
@@ -42,7 +43,7 @@ int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmd,
return 0;
}
}
#endif // x86/x64: AVX feature checks
return main( __argc, __argv );
}
#endif

View File

@@ -13,6 +13,24 @@ static inline uint64_t TracyLzcnt( uint64_t i )
{
return uint64_t( __builtin_clzll( i ) );
}
#elif defined(_M_ARM64)
#include <arm_neon.h>
static inline uint64_t TracyCountBits( uint64_t i )
{
uint8x8_t v = vreinterpret_u8_u64( vdup_n_u64( i ) );
uint8x8_t popcnt = vcnt_u8( v );
return (uint64_t)vaddlv_u8( popcnt );
}
static inline uint64_t TracyLzcnt( uint64_t i )
{
unsigned long index;
uint64_t leadingZeros = 64;
if( _BitScanReverse64( &index, i ) )
{
leadingZeros = leadingZeros - 1 - index;
}
return leadingZeros;
}
#elif defined _WIN64
# include <intrin.h>
# define TracyCountBits __popcnt64