diff --git a/Source/Engine/Platform/Win32/Win32Defines.h b/Source/Engine/Platform/Win32/Win32Defines.h index 891e86839..4571dc419 100644 --- a/Source/Engine/Platform/Win32/Win32Defines.h +++ b/Source/Engine/Platform/Win32/Win32Defines.h @@ -6,10 +6,14 @@ // Platform description #define PLATFORM_DESKTOP 1 -#if defined(WIN64) +#if defined(WIN64) && defined(_M_X64) #define PLATFORM_64BITS 1 #define PLATFORM_ARCH_X64 1 #define PLATFORM_ARCH ArchitectureType::x64 +#elif defined(WIN64) && defined(_M_ARM64) +#define PLATFORM_64BITS 1 +#define PLATFORM_ARCH_ARM64 1 +#define PLATFORM_ARCH ArchitectureType::ARM64 #else #define PLATFORM_64BITS 0 #define PLATFORM_ARCH_X86 1 diff --git a/Source/Engine/Platform/Win32/Win32Platform.cpp b/Source/Engine/Platform/Win32/Win32Platform.cpp index d46706621..a9aa784c2 100644 --- a/Source/Engine/Platform/Win32/Win32Platform.cpp +++ b/Source/Engine/Platform/Win32/Win32Platform.cpp @@ -157,10 +157,14 @@ bool Win32Platform::Init() CpuInfo.PageSize = siSysInfo.dwPageSize; CpuInfo.ClockSpeed = ClockFrequency; { +#ifdef _M_ARM64 + CpuInfo.CacheLineSize = 128; +#else int args[4]; __cpuid(args, 0x80000006); CpuInfo.CacheLineSize = args[2] & 0xFF; ASSERT(CpuInfo.CacheLineSize && Math::IsPowerOfTwo(CpuInfo.CacheLineSize)); +#endif } // Setup unique device ID @@ -226,10 +230,12 @@ void Win32Platform::MemoryBarrier() { _ReadWriteBarrier(); #if PLATFORM_64BITS -#ifdef _AMD64_ +#if defined(_AMD64_) __faststorefence(); #elif defined(_IA64_) __mf(); +#elif defined(_ARM64_) + __dmb(_ARM64_BARRIER_ISH); #else #error "Invalid platform." #endif @@ -243,7 +249,11 @@ void Win32Platform::MemoryBarrier() void Win32Platform::Prefetch(void const* ptr) { +#if _M_ARM64 + __prefetch((char const*)ptr); +#else _mm_prefetch((char const*)ptr, _MM_HINT_T0); +#endif } void* Win32Platform::Allocate(uint64 size, uint64 alignment) diff --git a/Source/Engine/Platform/Windows/WindowsPlatform.cpp b/Source/Engine/Platform/Windows/WindowsPlatform.cpp index ba450d7ee..0f1159fc5 100644 --- a/Source/Engine/Platform/Windows/WindowsPlatform.cpp +++ b/Source/Engine/Platform/Windows/WindowsPlatform.cpp @@ -1312,6 +1312,14 @@ Array WindowsPlatform::GetStackFrames(int32 skipCount, stack.AddrBStore.Mode = AddrModeFlat; stack.AddrStack.Offset = ctx.IntSp; stack.AddrStack.Mode = AddrModeFlat; +#elif _M_ARM64 + imageType = IMAGE_FILE_MACHINE_ARM64; + stack.AddrPC.Offset = ctx.Pc; + stack.AddrPC.Mode = AddrModeFlat; + stack.AddrFrame.Offset = ctx.Fp; + stack.AddrFrame.Mode = AddrModeFlat; + stack.AddrStack.Offset = ctx.Sp; + stack.AddrStack.Mode = AddrModeFlat; #else #error "Platform not supported!" #endif diff --git a/Source/Engine/Scripting/Runtime/DotNet.cpp b/Source/Engine/Scripting/Runtime/DotNet.cpp index a3ec1321f..25213ec46 100644 --- a/Source/Engine/Scripting/Runtime/DotNet.cpp +++ b/Source/Engine/Scripting/Runtime/DotNet.cpp @@ -1777,13 +1777,18 @@ bool InitHostfxr() { case PlatformType::Windows: case PlatformType::UWP: - platformStr = PLATFORM_64BITS ? "Windows x64" : "Windows x86"; + if (PLATFORM_ARCH == ArchitectureType::x64) + platformStr = "Windows x64"; + else if (PLATFORM_ARCH == ArchitectureType::ARM64) + platformStr = "Windows ARM64"; + else + platformStr = "Windows x86"; break; case PlatformType::Linux: - platformStr = PLATFORM_ARCH_ARM64 ? "Linux Arm64" : PLATFORM_ARCH_ARM ? "Linux Arm32" : PLATFORM_64BITS ? "Linux x64" : "Linux x86"; + platformStr = PLATFORM_ARCH_ARM64 ? "Linux ARM64" : PLATFORM_ARCH_ARM ? "Linux Arm32" : PLATFORM_64BITS ? "Linux x64" : "Linux x86"; break; case PlatformType::Mac: - platformStr = PLATFORM_ARCH_ARM || PLATFORM_ARCH_ARM64 ? "macOS Arm64" : PLATFORM_64BITS ? "macOS x64" : "macOS x86"; + platformStr = PLATFORM_ARCH_ARM || PLATFORM_ARCH_ARM64 ? "macOS ARM64" : PLATFORM_64BITS ? "macOS x64" : "macOS x86"; break; default:; platformStr = ""; diff --git a/Source/Engine/Scripting/ScriptingType.h b/Source/Engine/Scripting/ScriptingType.h index 17a844097..01335b6cb 100644 --- a/Source/Engine/Scripting/ScriptingType.h +++ b/Source/Engine/Scripting/ScriptingType.h @@ -493,6 +493,66 @@ FORCE_INLINE int32 GetVTableIndex(void** vtable, int32 entriesCount, void* func) if (op == 0x20) return 0; return *(byte*)funcJmp / sizeof(void*); +#elif defined(_MSC_VER) && PLATFORM_ARCH_ARM64 + // For MSVC ARM64, the following thunk takes a relative jump from the function pointer to the next thunk: + // adrp xip0, offset_high + // add xip0, xip0, offset_low + // br xip0 + // The last thunk contains the offset to the vtable: + // ldr xip0, [x0] + // ldr xip0, [xip0, XXX] + uint32_t* op = (uint32_t*)func; + + uint32_t def = *op; + if ((*op & 0x9F000000) == 0x90000000) + { + // adrp + uint32_t imm20 = (((*op & 0x60000000) >> 29) + ((*op & 0xFFFFE0) >> 3)) << 12; + op++; + + // add + def = *op; + uint32_t imm12 = (*op & 0x3FFC00) >> 10; + imm12 = (*op & 0x400000) != 0 ? (imm12 << 12) : imm12; + + // br + op = (uint32_t*)(((uintptr)func & ((uintptr)-1 << 12)) + imm20 + imm12) + 1; + + // ldr + offset + def = *op; + uint32_t offset = ((*op & 0x3FFC00) >> 10) * ((*op & 0x40000000) != 0 ? 8 : 4); + return offset / sizeof(void*); + } + else if ((*op & 0xBFC00000) == 0xB9400000) + { + // ldr + offset + uint32_t offset = ((*op & 0x3FFC00) >> 10) * ((*op & 0x40000000) != 0 ? 8 : 4); + op++; + + // ldr + offset + def = *op; + if ((*op & 0xBFE00C00) == 0xB8400400) + { + // offset is stored in the register as is + uint32_t postindex = (*op & 0x1FF000) >> 12; + offset = postindex; + return offset / sizeof(void*); + } + else if ((*op & 0xBFE00C00) == 0xB8400C00) + { + // offset is added to the value in base register... updated to the same register + uint32_t preindex = (*op & 0x1FF000) >> 12; + offset += preindex; + return offset / sizeof(void*); + } + else if ((*op & 0xBFC00000) == 0xB9400000) + { + // 20-bit offset + offset = ((*op & 0x3FFC00) >> 10) * ((*op & 0x40000000) != 0 ? 8 : 4); + return offset / sizeof(void*); + } + CRASH; + } #elif defined(__clang__) // On Clang member function pointer represents the offset from the vtable begin. return (int32)(intptr)func / sizeof(void*); diff --git a/Source/FlaxEditor.Build.cs b/Source/FlaxEditor.Build.cs index b6074e264..e77fcaade 100644 --- a/Source/FlaxEditor.Build.cs +++ b/Source/FlaxEditor.Build.cs @@ -56,6 +56,9 @@ public class FlaxEditor : EngineTarget case TargetArchitecture.x86: options.OutputFolder = Path.Combine(options.WorkingDirectory, "Binaries", "Editor", "Win32", options.Configuration.ToString()); break; + case TargetArchitecture.ARM64: + options.OutputFolder = Path.Combine(options.WorkingDirectory, "Binaries", "Editor", "ARM64", options.Configuration.ToString()); + break; default: throw new InvalidArchitectureException(options.Architecture, "Not supported Editor architecture."); } break; diff --git a/Source/Tools/Flax.Build/Build/Platform.cs b/Source/Tools/Flax.Build/Build/Platform.cs index 5fe01a93c..526dd2c54 100644 --- a/Source/Tools/Flax.Build/Build/Platform.cs +++ b/Source/Tools/Flax.Build/Build/Platform.cs @@ -286,11 +286,24 @@ namespace Flax.Build var subdir = "Binaries/Editor/"; switch (Platform.BuildTargetPlatform) { - case TargetPlatform.Windows: return subdir + "Win64"; + case TargetPlatform.Windows: + { + switch (Platform.BuildTargetArchitecture) + { + case TargetArchitecture.x64: + return subdir + "Win64"; + case TargetArchitecture.x86: + return subdir + "Win32"; + case TargetArchitecture.ARM64: + return subdir + "ARM64"; + default: + throw new NotImplementedException($"{Platform.BuildTargetPlatform}: {Platform.BuildTargetArchitecture}"); + } + } case TargetPlatform.Linux: return subdir + "Linux"; case TargetPlatform.Mac: return subdir + "Mac"; } - throw new NotImplementedException(); + throw new NotImplementedException(Platform.BuildTargetPlatform.ToString()); } /// @@ -306,7 +319,7 @@ namespace Flax.Build switch (targetPlatform) { - case TargetPlatform.Windows: return targetArchitecture == TargetArchitecture.x64 || targetArchitecture == TargetArchitecture.x86; + case TargetPlatform.Windows: return targetArchitecture == TargetArchitecture.x64 || targetArchitecture == TargetArchitecture.x86 || targetArchitecture == TargetArchitecture.ARM64; case TargetPlatform.XboxScarlett: return targetArchitecture == TargetArchitecture.x64; case TargetPlatform.XboxOne: return targetArchitecture == TargetArchitecture.x64; case TargetPlatform.UWP: return targetArchitecture == TargetArchitecture.x64; diff --git a/Source/Tools/Flax.Build/Platforms/Windows/WindowsPlatform.cs b/Source/Tools/Flax.Build/Platforms/Windows/WindowsPlatform.cs index 9d9a6913b..8fd361700 100644 --- a/Source/Tools/Flax.Build/Platforms/Windows/WindowsPlatform.cs +++ b/Source/Tools/Flax.Build/Platforms/Windows/WindowsPlatform.cs @@ -82,7 +82,7 @@ namespace Flax.Build.Platforms var outputType = project.OutputType ?? configuration.Target.OutputType; if (outputType != TargetOutputType.Executable && configuration.Name.StartsWith("Editor.")) { - var editorFolder = configuration.Architecture == TargetArchitecture.x64 ? "Win64" : "Win32"; + var editorFolder = configuration.Architecture == TargetArchitecture.x64 ? "Win64" : (configuration.Architecture == TargetArchitecture.ARM64 ? "ARM64" : "Win32"); vcUserFileContent.AppendLine(string.Format(" ", configuration.Name)); vcUserFileContent.AppendLine(string.Format(" {0}\\FlaxEditor.exe", Path.Combine(Globals.EngineRoot, "Binaries", "Editor", editorFolder, configuration.ConfigurationName))); vcUserFileContent.AppendLine(" -project \"$(SolutionDir)\" -skipCompile"); @@ -108,6 +108,9 @@ namespace Flax.Build.Platforms case TargetArchitecture.x64: name = "Win64"; break; + case TargetArchitecture.ARM64: + name = "ARM64"; + break; } } } diff --git a/Source/Tools/Flax.Build/Platforms/Windows/WindowsToolchain.cs b/Source/Tools/Flax.Build/Platforms/Windows/WindowsToolchain.cs index 121a7b367..3f74761c3 100644 --- a/Source/Tools/Flax.Build/Platforms/Windows/WindowsToolchain.cs +++ b/Source/Tools/Flax.Build/Platforms/Windows/WindowsToolchain.cs @@ -74,6 +74,12 @@ namespace Flax.Build.Platforms options.LinkEnv.InputLibraries.Add("ole32.lib"); options.LinkEnv.InputLibraries.Add("oleaut32.lib"); options.LinkEnv.InputLibraries.Add("delayimp.lib"); + + if (options.Architecture == TargetArchitecture.ARM64) + { + options.CompileEnv.PreprocessorDefinitions.Add("USE_SOFT_INTRINSICS"); + options.LinkEnv.InputLibraries.Add("softintrin.lib"); + } } /// diff --git a/Source/Tools/Flax.Build/Platforms/Windows/WindowsToolchainBase.cs b/Source/Tools/Flax.Build/Platforms/Windows/WindowsToolchainBase.cs index 252d9134d..8d5afbeae 100644 --- a/Source/Tools/Flax.Build/Platforms/Windows/WindowsToolchainBase.cs +++ b/Source/Tools/Flax.Build/Platforms/Windows/WindowsToolchainBase.cs @@ -405,7 +405,7 @@ namespace Flax.Build.Platforms options.CompileEnv.PreprocessorDefinitions.Add("_CRT_SECURE_NO_DEPRECATE"); options.CompileEnv.PreprocessorDefinitions.Add("_CRT_SECURE_NO_WARNINGS"); options.CompileEnv.PreprocessorDefinitions.Add("_WINDOWS"); - if (Architecture == TargetArchitecture.x64) + if (Architecture == TargetArchitecture.x64 || Architecture == TargetArchitecture.ARM64) options.CompileEnv.PreprocessorDefinitions.Add("WIN64"); } @@ -790,9 +790,11 @@ namespace Flax.Build.Platforms args.Add("/MACHINE:x64"); break; case TargetArchitecture.ARM: - case TargetArchitecture.ARM64: args.Add("/MACHINE:ARM"); break; + case TargetArchitecture.ARM64: + args.Add("/MACHINE:ARM64"); + break; default: throw new InvalidArchitectureException(Architecture); } diff --git a/Source/Tools/Flax.Build/Projects/VisualStudio/VCProjectGenerator.cs b/Source/Tools/Flax.Build/Projects/VisualStudio/VCProjectGenerator.cs index 13c728b30..fabae2b86 100644 --- a/Source/Tools/Flax.Build/Projects/VisualStudio/VCProjectGenerator.cs +++ b/Source/Tools/Flax.Build/Projects/VisualStudio/VCProjectGenerator.cs @@ -199,6 +199,26 @@ namespace Flax.Build.Projects.VisualStudio if (includePaths.Count != 0) vcProjectFileContent.AppendLine(string.Format(" $(NMakeIncludeSearchPath);{0}", string.Join(";", includePaths))); + var additionalOptions = new List(); + additionalOptions.Add("$(AdditionalOptions)"); + switch (configuration.TargetBuildOptions.CompileEnv.CppVersion) + { + case CppVersion.Cpp14: + additionalOptions.Add("/std:c++14"); + break; + case CppVersion.Cpp17: + additionalOptions.Add("/std:c++17"); + break; + case CppVersion.Cpp20: + additionalOptions.Add("/std:c++20"); + break; + case CppVersion.Latest: + additionalOptions.Add("/std:c++latest"); + break; + } + + vcProjectFileContent.AppendLine(string.Format(" {0}", string.Join(" ", additionalOptions))); + vcProjectFileContent.AppendLine(" "); } @@ -326,34 +346,18 @@ namespace Flax.Build.Projects.VisualStudio vcProjectFileContent.AppendLine(" "); vcFiltersFileContent.AppendLine(" "); - // IntelliSense information - - var additionalOptions = new List(); - switch (project.Configurations[0].TargetBuildOptions.CompileEnv.CppVersion) { - case CppVersion.Cpp14: - additionalOptions.Add("/std:c++14"); - break; - case CppVersion.Cpp17: - additionalOptions.Add("/std:c++17"); - break; - case CppVersion.Cpp20: - additionalOptions.Add("/std:c++20"); - break; - case CppVersion.Latest: - additionalOptions.Add("/std:c++latest"); - break; + // IntelliSense information + vcProjectFileContent.AppendLine(" "); + vcProjectFileContent.AppendLine(string.Format(" $(NMakePreprocessorDefinitions){0}", (project.Defines.Count > 0 ? (";" + string.Join(";", project.Defines)) : ""))); + vcProjectFileContent.AppendLine(string.Format(" $(NMakeIncludeSearchPath){0}", (project.SearchPaths.Length > 0 ? (";" + string.Join(";", project.SearchPaths)) : ""))); + vcProjectFileContent.AppendLine(" $(NMakeForcedIncludes)"); + vcProjectFileContent.AppendLine(" $(NMakeAssemblySearchPath)"); + vcProjectFileContent.AppendLine(" $(NMakeForcedUsingAssemblies)"); + vcProjectFileContent.AppendLine(" $(AdditionalOptions)"); + vcProjectFileContent.AppendLine(" "); } - vcProjectFileContent.AppendLine(" "); - vcProjectFileContent.AppendLine(string.Format(" $(NMakePreprocessorDefinitions){0}", (project.Defines.Count > 0 ? (";" + string.Join(";", project.Defines)) : ""))); - vcProjectFileContent.AppendLine(string.Format(" $(NMakeIncludeSearchPath){0}", (project.SearchPaths.Length > 0 ? (";" + string.Join(";", project.SearchPaths)) : ""))); - vcProjectFileContent.AppendLine(" $(NMakeForcedIncludes)"); - vcProjectFileContent.AppendLine(" $(NMakeAssemblySearchPath)"); - vcProjectFileContent.AppendLine(" $(NMakeForcedUsingAssemblies)"); - vcProjectFileContent.AppendLine(string.Format(" {0}", string.Join(" ", additionalOptions))); - vcProjectFileContent.AppendLine(" "); - foreach (var platform in platforms) { if (platform is IVisualStudioProjectCustomizer customizer)