diff --git a/msbuild/Xamarin.Mac.Tasks/Tasks/CompileSceneKitAssets.cs b/msbuild/Xamarin.Mac.Tasks/Tasks/CompileSceneKitAssets.cs index 9f26390e3e..2e3ed0fb2a 100644 --- a/msbuild/Xamarin.Mac.Tasks/Tasks/CompileSceneKitAssets.cs +++ b/msbuild/Xamarin.Mac.Tasks/Tasks/CompileSceneKitAssets.cs @@ -4,8 +4,5 @@ namespace Xamarin.Mac.Tasks { public class CompileSceneKitAssets : CompileSceneKitAssetsTaskBase { - protected override string OperatingSystem { - get { return "osx"; } - } } } diff --git a/msbuild/Xamarin.Mac.Tasks/Tasks/Metal.cs b/msbuild/Xamarin.Mac.Tasks/Tasks/Metal.cs index d3d9f0abb2..bc6f604202 100644 --- a/msbuild/Xamarin.Mac.Tasks/Tasks/Metal.cs +++ b/msbuild/Xamarin.Mac.Tasks/Tasks/Metal.cs @@ -6,10 +6,6 @@ namespace Xamarin.Mac.Tasks { public class Metal : MetalTaskBase { - protected override string OperatingSystem { - get { return "macosx"; } - } - #if !MTOUCH_TESTS protected override string MinimumDeploymentTargetKey { get { return ManifestKeys.LSMinimumSystemVersion; } diff --git a/msbuild/Xamarin.Mac.Tasks/Tasks/ScnTool.cs b/msbuild/Xamarin.Mac.Tasks/Tasks/ScnTool.cs index a6a10bd345..df1f7ecd12 100644 --- a/msbuild/Xamarin.Mac.Tasks/Tasks/ScnTool.cs +++ b/msbuild/Xamarin.Mac.Tasks/Tasks/ScnTool.cs @@ -4,8 +4,5 @@ namespace Xamarin.Mac.Tasks { public class ScnTool : ScnToolTaskBase { - protected override string OperatingSystem { - get { return "osx"; } - } } } diff --git a/msbuild/Xamarin.Mac.Tasks/Xamarin.Mac.Common.targets b/msbuild/Xamarin.Mac.Tasks/Xamarin.Mac.Common.targets index 9d84c0a1ef..da24850f77 100644 --- a/msbuild/Xamarin.Mac.Tasks/Xamarin.Mac.Common.targets +++ b/msbuild/Xamarin.Mac.Tasks/Xamarin.Mac.Common.targets @@ -340,8 +340,10 @@ Copyright (C) 2014 Xamarin. All rights reserved. IntermediateOutputPath="$(IntermediateOutputPath)" AppManifest="$(_AppManifest)" ProjectDir="$(MSBuildProjectDirectory)" + TargetFrameworkIdentifier="$(TargetFrameworkIdentifier)" ResourcePrefix="$(XamMacResourcePrefix)" SdkDevPath="$(_SdkDevPath)" + SdkIsSimulator="false" SdkRoot="$(_SdkRoot)" SdkVersion="$(MacOSXSdkVersion)" SourceFile="@(Metal)"> @@ -588,6 +590,7 @@ Copyright (C) 2014 Xamarin. All rights reserved. SdkRoot="$(_SdkRoot)" SdkDevPath="$(_SdkDevPath)" SdkVersion="$(MacOSXSdkVersion)" + TargetFrameworkIdentifier="$(TargetFrameworkIdentifier)" IntermediateOutputPath="$(IntermediateOutputPath)" InputScene="%(_ColladaAssetWithLogicalName.Identity)" OutputScene="$(IntermediateOutputPath)%(_ColladaAssetWithLogicalName.LogicalName)"> @@ -675,6 +678,7 @@ Copyright (C) 2014 Xamarin. All rights reserved. ToolPath="$(CopySceneKitAssetsPath)" SceneKitAssets="@(SceneKitAsset)" IntermediateOutputPath="$(IntermediateOutputPath)" + TargetFrameworkIdentifier="$(TargetFrameworkIdentifier)" ProjectDir="$(MSBuildProjectDirectory)" ResourcePrefix="$(XamMacResourcePrefix)" SdkPlatform="MacOSX" diff --git a/msbuild/Xamarin.MacDev.Tasks.Core/PlatformFramework.cs b/msbuild/Xamarin.MacDev.Tasks.Core/PlatformFramework.cs index efa5c78462..d2f6abd38d 100644 --- a/msbuild/Xamarin.MacDev.Tasks.Core/PlatformFramework.cs +++ b/msbuild/Xamarin.MacDev.Tasks.Core/PlatformFramework.cs @@ -54,5 +54,22 @@ namespace Xamarin.MacDev.Tasks throw new InvalidOperationException ("Unknown TargetFrameworkIdentifier: " + targetFrameworkIdentifier); } } + + public static string GetOperatingSystem (string targetFrameworkIdentifier) + { + var framework = PlatformFrameworkHelper.GetFramework (targetFrameworkIdentifier); + switch (framework) { + case PlatformFramework.WatchOS: + return "watchos"; + case PlatformFramework.TVOS: + return "tvos"; + case PlatformFramework.MacOS: + return "osx"; + case PlatformFramework.iOS: + return "ios"; + default: + throw new InvalidOperationException (string.Format ("Unknown target framework {0} for target framework identifier {2}.", framework, targetFrameworkIdentifier)); + } + } } } diff --git a/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/CompileSceneKitAssetsTaskBase.cs b/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/CompileSceneKitAssetsTaskBase.cs index 15da5851f8..12c39a8f0b 100644 --- a/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/CompileSceneKitAssetsTaskBase.cs +++ b/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/CompileSceneKitAssetsTaskBase.cs @@ -47,6 +47,9 @@ namespace Xamarin.MacDev.Tasks [Required] public string SdkVersion { get; set; } + [Required] + public string TargetFrameworkIdentifier { get; set; } + public string ToolExe { get { return toolExe ?? ToolName; } set { toolExe = value; } @@ -67,8 +70,10 @@ namespace Xamarin.MacDev.Tasks get { return "copySceneKitAssets"; } } - protected abstract string OperatingSystem { - get; + protected virtual string OperatingSystem { + get { + return PlatformFrameworkHelper.GetOperatingSystem (TargetFrameworkIdentifier); + } } string DeveloperRootBinDir { diff --git a/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/MetalTaskBase.cs b/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/MetalTaskBase.cs index d2123e2bb1..e4e1438a6d 100644 --- a/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/MetalTaskBase.cs +++ b/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/MetalTaskBase.cs @@ -33,12 +33,18 @@ namespace Xamarin.MacDev.Tasks [Required] public string SdkVersion { get; set; } + [Required] + public bool SdkIsSimulator { get; set; } + [Required] public string SdkRoot { get; set; } [Required] public ITaskItem SourceFile { get; set; } + [Required] + public string TargetFrameworkIdentifier { get; set; } + #endregion [Output] @@ -48,8 +54,22 @@ namespace Xamarin.MacDev.Tasks get; } - protected abstract string OperatingSystem { - get; + protected virtual string OperatingSystem { + get { + switch (PlatformFrameworkHelper.GetFramework (TargetFrameworkIdentifier)) { + case PlatformFramework.WatchOS: + return SdkIsSimulator ? "watchos-simulator" : "watchos"; + case PlatformFramework.TVOS: + return SdkIsSimulator ? "tvos-simulator" : "tvos"; + case PlatformFramework.MacOS: + return "macosx"; + case PlatformFramework.iOS: + return SdkIsSimulator ? "iphonesimulator" : "ios"; + default: + Log.LogError ($"Unknown target framework identifier: {TargetFrameworkIdentifier}."); + return string.Empty; + } + } } protected abstract string DevicePlatformBinDir { diff --git a/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/ScnToolTaskBase.cs b/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/ScnToolTaskBase.cs index a3f4206e90..ccbab4ad93 100644 --- a/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/ScnToolTaskBase.cs +++ b/msbuild/Xamarin.MacDev.Tasks.Core/Tasks/ScnToolTaskBase.cs @@ -39,14 +39,19 @@ namespace Xamarin.MacDev.Tasks } } + [Required] + public string TargetFrameworkIdentifier { get; set; } + #endregion string DevicePlatformBinDir { get { return Path.Combine (SdkDevPath, "usr", "bin"); } } - protected abstract string OperatingSystem { - get; + protected virtual string OperatingSystem { + get { + return PlatformFrameworkHelper.GetOperatingSystem (TargetFrameworkIdentifier); + } } protected override string ToolName { diff --git a/msbuild/Xamarin.iOS.Tasks.Core/Tasks/CompileSceneKitAssetsTaskBase.cs b/msbuild/Xamarin.iOS.Tasks.Core/Tasks/CompileSceneKitAssetsTaskBase.cs index 30a75aa363..8b2021c653 100644 --- a/msbuild/Xamarin.iOS.Tasks.Core/Tasks/CompileSceneKitAssetsTaskBase.cs +++ b/msbuild/Xamarin.iOS.Tasks.Core/Tasks/CompileSceneKitAssetsTaskBase.cs @@ -2,8 +2,5 @@ { public abstract class CompileSceneKitAssetsTaskBase : Xamarin.MacDev.Tasks.CompileSceneKitAssetsTaskBase { - protected override string OperatingSystem { - get { return "ios"; } - } } } diff --git a/msbuild/Xamarin.iOS.Tasks.Core/Tasks/MetalTaskBase.cs b/msbuild/Xamarin.iOS.Tasks.Core/Tasks/MetalTaskBase.cs index 52450a3b28..ccbdd47e16 100644 --- a/msbuild/Xamarin.iOS.Tasks.Core/Tasks/MetalTaskBase.cs +++ b/msbuild/Xamarin.iOS.Tasks.Core/Tasks/MetalTaskBase.cs @@ -6,10 +6,6 @@ namespace Xamarin.iOS.Tasks { public abstract class MetalTaskBase : Xamarin.MacDev.Tasks.MetalTaskBase { - protected override string OperatingSystem { - get { return "ios"; } - } - protected override string MinimumDeploymentTargetKey { get { return ManifestKeys.MinimumOSVersion; } } diff --git a/msbuild/Xamarin.iOS.Tasks.Core/Tasks/ScnToolTaskBase.cs b/msbuild/Xamarin.iOS.Tasks.Core/Tasks/ScnToolTaskBase.cs index c0696e69b8..3ffe79e6cf 100644 --- a/msbuild/Xamarin.iOS.Tasks.Core/Tasks/ScnToolTaskBase.cs +++ b/msbuild/Xamarin.iOS.Tasks.Core/Tasks/ScnToolTaskBase.cs @@ -2,8 +2,5 @@ { public abstract class ScnToolTaskBase : Xamarin.MacDev.Tasks.ScnToolTaskBase { - protected override string OperatingSystem { - get { return "ios"; } - } } } diff --git a/msbuild/Xamarin.iOS.Tasks.Core/Xamarin.iOS.Common.targets b/msbuild/Xamarin.iOS.Tasks.Core/Xamarin.iOS.Common.targets index b5e69bf865..26a2fb9e54 100644 --- a/msbuild/Xamarin.iOS.Tasks.Core/Xamarin.iOS.Common.targets +++ b/msbuild/Xamarin.iOS.Tasks.Core/Xamarin.iOS.Common.targets @@ -595,16 +595,16 @@ Copyright (C) 2013-2016 Xamarin. All rights reserved. - - @@ -1220,6 +1220,7 @@ Copyright (C) 2013-2016 Xamarin. All rights reserved. SdkRoot="$(_SdkRoot)" SdkDevPath="$(_SdkDevPath)" SdkVersion="$(MtouchSdkVersion)" + TargetFrameworkIdentifier="$(TargetFrameworkIdentifier)" IntermediateOutputPath="$(DeviceSpecificIntermediateOutputPath)" InputScene="%(_ColladaAssetWithLogicalName.Identity)" OutputScene="$(DeviceSpecificIntermediateOutputPath)%(_ColladaAssetWithLogicalName.LogicalName)"> @@ -1333,6 +1334,7 @@ Copyright (C) 2013-2016 Xamarin. All rights reserved. ToolPath="$(CopySceneKitAssetsPath)" SceneKitAssets="@(SceneKitAsset)" IntermediateOutputPath="$(DeviceSpecificIntermediateOutputPath)" + TargetFrameworkIdentifier="$(TargetFrameworkIdentifier)" ProjectDir="$(MSBuildProjectDirectory)" ResourcePrefix="$(IPhoneResourcePrefix)" IsWatchApp="$(IsWatchApp)" diff --git a/msbuild/tests/MyMetalGame/GameViewController.cs b/msbuild/tests/MyMetalGame/GameViewController.cs index b5da97593e..9999adb808 100644 --- a/msbuild/tests/MyMetalGame/GameViewController.cs +++ b/msbuild/tests/MyMetalGame/GameViewController.cs @@ -208,6 +208,8 @@ namespace MyMetalGame // If we need a depth texture and don't have one, or if the depth texture we have is the wrong size // Then allocate one of the proper size MTLTextureDescriptor desc = MTLTextureDescriptor.CreateTexture2DDescriptor (MTLPixelFormat.Depth32Float, texture.Width, texture.Height, false); + if (ObjCRuntime.Runtime.Arch == ObjCRuntime.Arch.SIMULATOR) + desc.StorageMode = MTLStorageMode.Private; depthTex = device.CreateTexture (desc); depthTex.Label = "Depth"; diff --git a/msbuild/tests/MyMetalGame/MyMetalGame.sln b/msbuild/tests/MyMetalGame/MyMetalGame.sln new file mode 100644 index 0000000000..496a3e6f2e --- /dev/null +++ b/msbuild/tests/MyMetalGame/MyMetalGame.sln @@ -0,0 +1,23 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyMetalGame", "MyMetalGame.csproj", "{4598E620-3F15-4F66-B01A-B7F9E45CE659}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|iPhoneSimulator = Debug|iPhoneSimulator + Release|iPhoneSimulator = Release|iPhoneSimulator + Debug|iPhone = Debug|iPhone + Release|iPhone = Release|iPhone + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4598E620-3F15-4F66-B01A-B7F9E45CE659}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator + {4598E620-3F15-4F66-B01A-B7F9E45CE659}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator + {4598E620-3F15-4F66-B01A-B7F9E45CE659}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator + {4598E620-3F15-4F66-B01A-B7F9E45CE659}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator + {4598E620-3F15-4F66-B01A-B7F9E45CE659}.Debug|iPhone.ActiveCfg = Debug|iPhone + {4598E620-3F15-4F66-B01A-B7F9E45CE659}.Debug|iPhone.Build.0 = Debug|iPhone + {4598E620-3F15-4F66-B01A-B7F9E45CE659}.Release|iPhone.ActiveCfg = Release|iPhone + {4598E620-3F15-4F66-B01A-B7F9E45CE659}.Release|iPhone.Build.0 = Release|iPhone + EndGlobalSection +EndGlobal diff --git a/msbuild/tests/MyTVMetalGame/AppDelegate.cs b/msbuild/tests/MyTVMetalGame/AppDelegate.cs new file mode 100644 index 0000000000..06c401b519 --- /dev/null +++ b/msbuild/tests/MyTVMetalGame/AppDelegate.cs @@ -0,0 +1,56 @@ +using Foundation; +using UIKit; + +namespace MyTVMetalGame { + // The UIApplicationDelegate for the application. This class is responsible for launching the + // User Interface of the application, as well as listening (and optionally responding) to application events from iOS. + [Register ("AppDelegate")] + public class AppDelegate : UIApplicationDelegate { + // class-level declarations + + public override UIWindow Window { + get; + set; + } + + public override bool FinishedLaunching (UIApplication application, NSDictionary launchOptions) + { + // Override point for customization after application launch. + // If not required for your application you can safely delete this method + + return true; + } + + public override void OnResignActivation (UIApplication application) + { + // Invoked when the application is about to move from active to inactive state. + // This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) + // or when the user quits the application and it begins the transition to the background state. + // Games should use this method to pause the game. + } + + public override void DidEnterBackground (UIApplication application) + { + // Use this method to release shared resources, save user data, invalidate timers and store the application state. + // If your application supports background exection this method is called instead of WillTerminate when the user quits. + } + + public override void WillEnterForeground (UIApplication application) + { + // Called as part of the transiton from background to active state. + // Here you can undo many of the changes made on entering the background. + } + + public override void OnActivated (UIApplication application) + { + // Restart any tasks that were paused (or not yet started) while the application was inactive. + // If the application was previously in the background, optionally refresh the user interface. + } + + public override void WillTerminate (UIApplication application) + { + // Called when the application is about to terminate. Save data, if needed. See also DidEnterBackground. + } + } +} + diff --git a/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/Contents.json b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/Contents.json new file mode 100644 index 0000000000..3767d60b0e --- /dev/null +++ b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,54 @@ +{ + "images": [ + { + "idiom": "universal" + }, + { + "scale": "1x", + "idiom": "universal" + }, + { + "scale": "2x", + "idiom": "universal" + }, + { + "scale": "3x", + "idiom": "universal" + }, + { + "idiom": "iphone" + }, + { + "scale": "1x", + "idiom": "iphone" + }, + { + "scale": "2x", + "idiom": "iphone" + }, + { + "subtype": "retina4", + "scale": "2x", + "idiom": "iphone" + }, + { + "scale": "3x", + "idiom": "iphone" + }, + { + "idiom": "ipad" + }, + { + "scale": "1x", + "idiom": "ipad" + }, + { + "scale": "2x", + "idiom": "ipad" + } + ], + "info": { + "version": 1, + "author": "xcode" + } +} \ No newline at end of file diff --git a/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Contents.json b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Contents.json new file mode 100644 index 0000000000..da4a164c91 --- /dev/null +++ b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Contents.json b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Contents.json new file mode 100644 index 0000000000..d29f024ed5 --- /dev/null +++ b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Contents.json @@ -0,0 +1,17 @@ +{ + "layers" : [ + { + "filename" : "Front.imagestacklayer" + }, + { + "filename" : "Middle.imagestacklayer" + }, + { + "filename" : "Back.imagestacklayer" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/Contents.json b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/Contents.json new file mode 100644 index 0000000000..3767d60b0e --- /dev/null +++ b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,54 @@ +{ + "images": [ + { + "idiom": "universal" + }, + { + "scale": "1x", + "idiom": "universal" + }, + { + "scale": "2x", + "idiom": "universal" + }, + { + "scale": "3x", + "idiom": "universal" + }, + { + "idiom": "iphone" + }, + { + "scale": "1x", + "idiom": "iphone" + }, + { + "scale": "2x", + "idiom": "iphone" + }, + { + "subtype": "retina4", + "scale": "2x", + "idiom": "iphone" + }, + { + "scale": "3x", + "idiom": "iphone" + }, + { + "idiom": "ipad" + }, + { + "scale": "1x", + "idiom": "ipad" + }, + { + "scale": "2x", + "idiom": "ipad" + } + ], + "info": { + "version": 1, + "author": "xcode" + } +} \ No newline at end of file diff --git a/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Contents.json b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Contents.json new file mode 100644 index 0000000000..da4a164c91 --- /dev/null +++ b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json new file mode 100644 index 0000000000..3767d60b0e --- /dev/null +++ b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,54 @@ +{ + "images": [ + { + "idiom": "universal" + }, + { + "scale": "1x", + "idiom": "universal" + }, + { + "scale": "2x", + "idiom": "universal" + }, + { + "scale": "3x", + "idiom": "universal" + }, + { + "idiom": "iphone" + }, + { + "scale": "1x", + "idiom": "iphone" + }, + { + "scale": "2x", + "idiom": "iphone" + }, + { + "subtype": "retina4", + "scale": "2x", + "idiom": "iphone" + }, + { + "scale": "3x", + "idiom": "iphone" + }, + { + "idiom": "ipad" + }, + { + "scale": "1x", + "idiom": "ipad" + }, + { + "scale": "2x", + "idiom": "ipad" + } + ], + "info": { + "version": 1, + "author": "xcode" + } +} \ No newline at end of file diff --git a/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Contents.json b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Contents.json new file mode 100644 index 0000000000..da4a164c91 --- /dev/null +++ b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/Contents.json b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/Contents.json new file mode 100644 index 0000000000..3767d60b0e --- /dev/null +++ b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,54 @@ +{ + "images": [ + { + "idiom": "universal" + }, + { + "scale": "1x", + "idiom": "universal" + }, + { + "scale": "2x", + "idiom": "universal" + }, + { + "scale": "3x", + "idiom": "universal" + }, + { + "idiom": "iphone" + }, + { + "scale": "1x", + "idiom": "iphone" + }, + { + "scale": "2x", + "idiom": "iphone" + }, + { + "subtype": "retina4", + "scale": "2x", + "idiom": "iphone" + }, + { + "scale": "3x", + "idiom": "iphone" + }, + { + "idiom": "ipad" + }, + { + "scale": "1x", + "idiom": "ipad" + }, + { + "scale": "2x", + "idiom": "ipad" + } + ], + "info": { + "version": 1, + "author": "xcode" + } +} \ No newline at end of file diff --git a/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Contents.json b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Contents.json new file mode 100644 index 0000000000..da4a164c91 --- /dev/null +++ b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Contents.json b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Contents.json new file mode 100644 index 0000000000..d29f024ed5 --- /dev/null +++ b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Contents.json @@ -0,0 +1,17 @@ +{ + "layers" : [ + { + "filename" : "Front.imagestacklayer" + }, + { + "filename" : "Middle.imagestacklayer" + }, + { + "filename" : "Back.imagestacklayer" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/Contents.json b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/Contents.json new file mode 100644 index 0000000000..3767d60b0e --- /dev/null +++ b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,54 @@ +{ + "images": [ + { + "idiom": "universal" + }, + { + "scale": "1x", + "idiom": "universal" + }, + { + "scale": "2x", + "idiom": "universal" + }, + { + "scale": "3x", + "idiom": "universal" + }, + { + "idiom": "iphone" + }, + { + "scale": "1x", + "idiom": "iphone" + }, + { + "scale": "2x", + "idiom": "iphone" + }, + { + "subtype": "retina4", + "scale": "2x", + "idiom": "iphone" + }, + { + "scale": "3x", + "idiom": "iphone" + }, + { + "idiom": "ipad" + }, + { + "scale": "1x", + "idiom": "ipad" + }, + { + "scale": "2x", + "idiom": "ipad" + } + ], + "info": { + "version": 1, + "author": "xcode" + } +} \ No newline at end of file diff --git a/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Contents.json b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Contents.json new file mode 100644 index 0000000000..da4a164c91 --- /dev/null +++ b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json new file mode 100644 index 0000000000..3767d60b0e --- /dev/null +++ b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json @@ -0,0 +1,54 @@ +{ + "images": [ + { + "idiom": "universal" + }, + { + "scale": "1x", + "idiom": "universal" + }, + { + "scale": "2x", + "idiom": "universal" + }, + { + "scale": "3x", + "idiom": "universal" + }, + { + "idiom": "iphone" + }, + { + "scale": "1x", + "idiom": "iphone" + }, + { + "scale": "2x", + "idiom": "iphone" + }, + { + "subtype": "retina4", + "scale": "2x", + "idiom": "iphone" + }, + { + "scale": "3x", + "idiom": "iphone" + }, + { + "idiom": "ipad" + }, + { + "scale": "1x", + "idiom": "ipad" + }, + { + "scale": "2x", + "idiom": "ipad" + } + ], + "info": { + "version": 1, + "author": "xcode" + } +} \ No newline at end of file diff --git a/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Contents.json b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Contents.json new file mode 100644 index 0000000000..da4a164c91 --- /dev/null +++ b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json new file mode 100644 index 0000000000..dea6e49fd5 --- /dev/null +++ b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json @@ -0,0 +1,32 @@ +{ + "assets" : [ + { + "size" : "1280x768", + "idiom" : "tv", + "filename" : "App Icon - Large.imagestack", + "role" : "primary-app-icon" + }, + { + "size" : "400x240", + "idiom" : "tv", + "filename" : "App Icon - Small.imagestack", + "role" : "primary-app-icon" + }, + { + "size" : "2320x720", + "idiom" : "tv", + "filename" : "Top Shelf Image Wide.imageset", + "role" : "top-shelf-image-wide" + }, + { + "size" : "1920x720", + "idiom" : "tv", + "filename" : "Top Shelf Image.imageset", + "role" : "top-shelf-image" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json new file mode 100644 index 0000000000..3767d60b0e --- /dev/null +++ b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json @@ -0,0 +1,54 @@ +{ + "images": [ + { + "idiom": "universal" + }, + { + "scale": "1x", + "idiom": "universal" + }, + { + "scale": "2x", + "idiom": "universal" + }, + { + "scale": "3x", + "idiom": "universal" + }, + { + "idiom": "iphone" + }, + { + "scale": "1x", + "idiom": "iphone" + }, + { + "scale": "2x", + "idiom": "iphone" + }, + { + "subtype": "retina4", + "scale": "2x", + "idiom": "iphone" + }, + { + "scale": "3x", + "idiom": "iphone" + }, + { + "idiom": "ipad" + }, + { + "scale": "1x", + "idiom": "ipad" + }, + { + "scale": "2x", + "idiom": "ipad" + } + ], + "info": { + "version": 1, + "author": "xcode" + } +} \ No newline at end of file diff --git a/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json new file mode 100644 index 0000000000..3767d60b0e --- /dev/null +++ b/msbuild/tests/MyTVMetalGame/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json @@ -0,0 +1,54 @@ +{ + "images": [ + { + "idiom": "universal" + }, + { + "scale": "1x", + "idiom": "universal" + }, + { + "scale": "2x", + "idiom": "universal" + }, + { + "scale": "3x", + "idiom": "universal" + }, + { + "idiom": "iphone" + }, + { + "scale": "1x", + "idiom": "iphone" + }, + { + "scale": "2x", + "idiom": "iphone" + }, + { + "subtype": "retina4", + "scale": "2x", + "idiom": "iphone" + }, + { + "scale": "3x", + "idiom": "iphone" + }, + { + "idiom": "ipad" + }, + { + "scale": "1x", + "idiom": "ipad" + }, + { + "scale": "2x", + "idiom": "ipad" + } + ], + "info": { + "version": 1, + "author": "xcode" + } +} \ No newline at end of file diff --git a/msbuild/tests/MyTVMetalGame/Assets.xcassets/Contents.json b/msbuild/tests/MyTVMetalGame/Assets.xcassets/Contents.json new file mode 100644 index 0000000000..da4a164c91 --- /dev/null +++ b/msbuild/tests/MyTVMetalGame/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/msbuild/tests/MyTVMetalGame/Entitlements.plist b/msbuild/tests/MyTVMetalGame/Entitlements.plist new file mode 100644 index 0000000000..5ea1ec76e1 --- /dev/null +++ b/msbuild/tests/MyTVMetalGame/Entitlements.plist @@ -0,0 +1,6 @@ + + + + + + diff --git a/msbuild/tests/MyTVMetalGame/GameViewController.cs b/msbuild/tests/MyTVMetalGame/GameViewController.cs new file mode 100644 index 0000000000..2f30e4b138 --- /dev/null +++ b/msbuild/tests/MyTVMetalGame/GameViewController.cs @@ -0,0 +1,366 @@ +using System; +using System.Runtime.InteropServices; +using System.Threading; + +using CoreAnimation; +using CoreGraphics; +using Foundation; +using OpenTK; +using Metal; +using UIKit; + +namespace MyTVMetalGame { + public partial class GameViewController : UIViewController { + struct Uniforms { + public Matrix4 ModelviewProjectionMatrix; + public Matrix4 NormalMatrix; + } + + // The max number of command buffers in flight + const int max_inflight_buffers = 3; + + // Max API memory buffer size + const int max_bytes_per_frame = 1024 * 1024; + + float [] cubeVertexData = { + // Data layout for each line below is: + // positionX, positionY, positionZ, normalX, normalY, normalZ, + 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, + -0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, + -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, + 0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, + 0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, + -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, + + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, + 0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, + 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, + 0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, + 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, + 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, + + -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, + 0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, + 0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, + -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, + -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, + 0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, + + -0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, + -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, + -0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, + -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, + -0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, + -0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, + + 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, + -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, + -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, + 0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, + 0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, + + 0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, + -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, + -0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, + 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, + 0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, + -0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f + }; + + // Layer + CAMetalLayer metalLayer; + MTLRenderPassDescriptor renderPassDescriptor; + + // Controller + CADisplayLink timer; + Semaphore inflightSemaphore; + IMTLBuffer dynamicConstantBuffer; + byte constantDataBufferIndex; + + // Renderer + IMTLDevice device; + IMTLCommandQueue commandQueue; + IMTLLibrary defaultLibrary; + IMTLRenderPipelineState pipelineState; + IMTLBuffer vertexBuffer; + IMTLDepthStencilState depthState; + IMTLTexture depthTex; + + // Uniforms + Matrix4 projectionMatrix; + Matrix4 viewMatrix; + Uniforms uniformBuffer; + float rotation; + + public GameViewController (IntPtr handle) : base (handle) + { + } + + public override void ViewDidLoad () + { + base.ViewDidLoad (); + + constantDataBufferIndex = 0; + inflightSemaphore = new Semaphore (max_inflight_buffers, max_inflight_buffers); + + SetupMetal (); + LoadAssets (); + + timer = CADisplayLink.Create (Gameloop); + timer.FrameInterval = 1; + timer.AddToRunLoop (NSRunLoop.Main, NSRunLoop.NSDefaultRunLoopMode); + } + + public override void DidReceiveMemoryWarning () + { + base.DidReceiveMemoryWarning (); + // Dispose of any resources that can be recreated. + } + + void SetupMetal () + { + // Find a usable device + device = MTLDevice.SystemDefault; + + // Create a new command queue + commandQueue = device.CreateCommandQueue (); + + // Load all the shader files with a metal file extension in the project + NSError error; + + defaultLibrary = device.CreateLibrary ("default.metallib", out error); + + // Setup metal layer and add as sub layer to view + metalLayer = new CAMetalLayer (); + metalLayer.Device = device; + metalLayer.PixelFormat = MTLPixelFormat.BGRA8Unorm; + + // Change this to NO if the compute encoder is used as the last pass on the drawable texture + metalLayer.FramebufferOnly = true; + + // Add metal layer to the views layer hierarchy + metalLayer.Frame = View.Layer.Frame; + View.Layer.AddSublayer (metalLayer); + + View.Opaque = true; + View.BackgroundColor = null; + View.ContentScaleFactor = UIScreen.MainScreen.Scale; + } + + void LoadAssets () + { + // Allocate one region of memory for the uniform buffer + dynamicConstantBuffer = device.CreateBuffer (max_bytes_per_frame, 0); + dynamicConstantBuffer.Label = "UniformBuffer"; + + // Load the fragment program into the library + IMTLFunction fragmentProgram = defaultLibrary.CreateFunction ("lighting_fragment"); + + // Load the vertex program into the library + IMTLFunction vertexProgram = defaultLibrary.CreateFunction ("lighting_vertex"); + + // Setup the vertex buffers + vertexBuffer = device.CreateBuffer (cubeVertexData, (MTLResourceOptions)0); + vertexBuffer.Label = "Vertices"; + + // Create a reusable pipeline state + var pipelineStateDescriptor = new MTLRenderPipelineDescriptor { + Label = "MyPipeline", + SampleCount = 1, + VertexFunction = vertexProgram, + FragmentFunction = fragmentProgram, + DepthAttachmentPixelFormat = MTLPixelFormat.Depth32Float + }; + + pipelineStateDescriptor.ColorAttachments [0].PixelFormat = MTLPixelFormat.BGRA8Unorm; + + NSError error; + + pipelineState = device.CreateRenderPipelineState (pipelineStateDescriptor, out error); + + if (pipelineState == null) + Console.WriteLine ("Failed to created pipeline state, error " + error); + + var depthStateDesc = new MTLDepthStencilDescriptor { + DepthCompareFunction = MTLCompareFunction.Less, + DepthWriteEnabled = true + }; + + depthState = device.CreateDepthStencilState (depthStateDesc); + } + + void SetupRenderPassDescriptorForTexture (IMTLTexture texture) + { + if (renderPassDescriptor == null) + renderPassDescriptor = MTLRenderPassDescriptor.CreateRenderPassDescriptor (); + + renderPassDescriptor.ColorAttachments [0].Texture = texture; + renderPassDescriptor.ColorAttachments [0].LoadAction = MTLLoadAction.Clear; + renderPassDescriptor.ColorAttachments [0].ClearColor = new MTLClearColor (0.65f, 0.65f, 0.65f, 1.0f); + renderPassDescriptor.ColorAttachments [0].StoreAction = MTLStoreAction.Store; + + if (depthTex == null || (depthTex.Width != texture.Width || depthTex.Height != texture.Height)) { + // If we need a depth texture and don't have one, or if the depth texture we have is the wrong size + // Then allocate one of the proper size + MTLTextureDescriptor desc = MTLTextureDescriptor.CreateTexture2DDescriptor (MTLPixelFormat.Depth32Float, texture.Width, texture.Height, false); + if (ObjCRuntime.Runtime.Arch == ObjCRuntime.Arch.SIMULATOR) + desc.StorageMode = MTLStorageMode.Private; depthTex = device.CreateTexture (desc); + depthTex.Label = "Depth"; + + renderPassDescriptor.DepthAttachment.Texture = depthTex; + renderPassDescriptor.DepthAttachment.LoadAction = MTLLoadAction.Clear; + renderPassDescriptor.DepthAttachment.ClearDepth = 1.0f; + renderPassDescriptor.DepthAttachment.StoreAction = MTLStoreAction.DontCare; + } + } + + void Render () + { + inflightSemaphore.WaitOne (); + + Update (); + + // Create a new command buffer for each renderpass to the current drawable + IMTLCommandBuffer commandBuffer = commandQueue.CommandBuffer (); + commandBuffer.Label = "MyCommand"; + + // Obtain a drawable texture for this render pass and set up the renderpass descriptor for the command encoder to render into + ICAMetalDrawable drawable = GetCurrentDrawable (); + + SetupRenderPassDescriptorForTexture (drawable.Texture); + + // Create a render command encoder so we can render into something + IMTLRenderCommandEncoder renderEncoder = commandBuffer.CreateRenderCommandEncoder (renderPassDescriptor); + renderEncoder.Label = "MyRenderEncoder"; + renderEncoder.SetDepthStencilState (depthState); + + // Set context state + renderEncoder.PushDebugGroup ("DrawCube"); + renderEncoder.SetRenderPipelineState (pipelineState); + renderEncoder.SetVertexBuffer (vertexBuffer, 0, 0); + renderEncoder.SetVertexBuffer (dynamicConstantBuffer, (nuint)(Marshal.SizeOf (typeof (Uniforms)) * constantDataBufferIndex), 1); + + // Tell the render context we want to draw our primitives + renderEncoder.DrawPrimitives (MTLPrimitiveType.Triangle, 0, 36, 1); + renderEncoder.PopDebugGroup (); + + // We're done encoding commands + renderEncoder.EndEncoding (); + + // Call the view's completion handler which is required by the view since it will signal its semaphore and set up the next buffer + commandBuffer.AddCompletedHandler (buffer => { + drawable.Dispose (); + inflightSemaphore.Release (); + }); + + // Schedule a present once the framebuffer is complete + commandBuffer.PresentDrawable (drawable); + + // Finalize rendering here & push the command buffer to the GPU + commandBuffer.Commit (); + + // The renderview assumes it can now increment the buffer index and that the previous index won't be touched until we cycle back around to the same index + constantDataBufferIndex = (byte)((constantDataBufferIndex + 1) % max_inflight_buffers); + } + + void Reshape () + { + // When reshape is called, update the view and projection matricies since this means the view orientation or size changed + var aspect = (float)(View.Bounds.Size.Width / View.Bounds.Size.Height); + projectionMatrix = CreateMatrixFromPerspective (65.0f * ((float)Math.PI / 180.0f), aspect, 0.1f, 100.0f); + + viewMatrix = Matrix4.Identity; + } + + void Update () + { + var baseModel = Matrix4.Mult (CreateMatrixFromTranslation (0.0f, 0.0f, 5.0f), CreateMatrixFromRotation (rotation, 0.0f, 1.0f, 0.0f)); + var baseMv = Matrix4.Mult (viewMatrix, baseModel); + var modelViewMatrix = Matrix4.Mult (baseMv, CreateMatrixFromRotation (rotation, 1.0f, 1.0f, 1.0f)); + + uniformBuffer.NormalMatrix = Matrix4.Invert (Matrix4.Transpose (modelViewMatrix)); + uniformBuffer.ModelviewProjectionMatrix = Matrix4.Transpose (Matrix4.Mult (projectionMatrix, modelViewMatrix)); + + // Copy uniformBuffer's content into dynamicConstantBuffer.Contents + int rawsize = Marshal.SizeOf (typeof (Uniforms)); + var rawdata = new byte [rawsize]; + IntPtr ptr = Marshal.AllocHGlobal (rawsize); + Marshal.StructureToPtr (uniformBuffer, ptr, false); + Marshal.Copy (ptr, rawdata, 0, rawsize); + Marshal.FreeHGlobal (ptr); + + Marshal.Copy (rawdata, 0, dynamicConstantBuffer.Contents + rawsize * constantDataBufferIndex, rawsize); + + rotation += 0.01f; + } + + // The main game loop called by the CADisplayLine timer + public void Gameloop () + { + Render (); + } + + // Called whenever view changes orientation or layout is changed + public override void ViewDidLayoutSubviews () + { + Reshape (); + } + + ICAMetalDrawable GetCurrentDrawable () + { + ICAMetalDrawable currentDrawable = null; + + while (currentDrawable == null) { + currentDrawable = metalLayer.NextDrawable (); + if (currentDrawable == null) + Console.WriteLine ("CurrentDrawable is null"); + } + + return currentDrawable; + } + + static Matrix4 CreateMatrixFromPerspective (float fovY, float aspect, float nearZ, float farZ) + { + float yscale = 1.0f / (float)Math.Tan (fovY * 0.5f); + float xscale = yscale / aspect; + float q = farZ / (farZ - nearZ); + + var m = new Matrix4 { + Row0 = new Vector4 (xscale, 0.0f, 0.0f, 0.0f), + Row1 = new Vector4 (0.0f, yscale, 0.0f, 0.0f), + Row2 = new Vector4 (0.0f, 0.0f, q, q * -nearZ), + Row3 = new Vector4 (0.0f, 0.0f, 1.0f, 0.0f) + }; + + return m; + } + + static Matrix4 CreateMatrixFromTranslation (float x, float y, float z) + { + var m = Matrix4.Identity; + m.Row0.W = x; + m.Row1.W = y; + m.Row2.W = z; + m.Row3.W = 1.0f; + return m; + } + + static Matrix4 CreateMatrixFromRotation (float radians, float x, float y, float z) + { + Vector3 v = Vector3.Normalize (new Vector3 (x, y, z)); + var cos = (float)Math.Cos (radians); + var sin = (float)Math.Sin (radians); + float cosp = 1.0f - cos; + + var m = new Matrix4 { + Row0 = new Vector4 (cos + cosp * v.X * v.X, cosp * v.X * v.Y - v.Z * sin, cosp * v.X * v.Z + v.Y * sin, 0.0f), + Row1 = new Vector4 (cosp * v.X * v.Y + v.Z * sin, cos + cosp * v.Y * v.Y, cosp * v.Y * v.Z - v.X * sin, 0.0f), + Row2 = new Vector4 (cosp * v.X * v.Z - v.Y * sin, cosp * v.Y * v.Z + v.X * sin, cos + cosp * v.Z * v.Z, 0.0f), + Row3 = new Vector4 (0.0f, 0.0f, 0.0f, 1.0f) + }; + + return m; + } + } +} diff --git a/msbuild/tests/MyTVMetalGame/GameViewController.designer.cs b/msbuild/tests/MyTVMetalGame/GameViewController.designer.cs new file mode 100644 index 0000000000..df0cae3777 --- /dev/null +++ b/msbuild/tests/MyTVMetalGame/GameViewController.designer.cs @@ -0,0 +1,11 @@ +using Foundation; +using System.CodeDom.Compiler; + +namespace MyTVMetalGame { + [Register ("GameViewController")] + partial class GameViewController { + void ReleaseDesignerOutlets () + { + } + } +} diff --git a/msbuild/tests/MyTVMetalGame/Info.plist b/msbuild/tests/MyTVMetalGame/Info.plist new file mode 100644 index 0000000000..ebb4fa7dbc --- /dev/null +++ b/msbuild/tests/MyTVMetalGame/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDisplayName + MyTVMetalGame + CFBundleName + MyTVMetalGame + CFBundleIdentifier + com.xamarin.MyTVMetalGame + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1.0 + MinimumOSVersion + 13.0 + UIDeviceFamily + + 3 + + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + arm64 + + GCSupportedGameControllers + + + ProfileName + ExtendedGamepad + + + ProfileName + MicroGamepad + + + GCSupportsControllerUserInteraction + + XSAppIconAssets + Assets.xcassets/App Icon & Top Shelf Image.brandassets + XSLaunchImageAssets + Assets.xcassets/LaunchImages.launchimage + + diff --git a/msbuild/tests/MyTVMetalGame/Main.cs b/msbuild/tests/MyTVMetalGame/Main.cs new file mode 100644 index 0000000000..d3e9ecbc84 --- /dev/null +++ b/msbuild/tests/MyTVMetalGame/Main.cs @@ -0,0 +1,13 @@ +using UIKit; + +namespace MyTVMetalGame { + public class Application { + // This is the main entry point of the application. + static void Main (string [] args) + { + // if you want to use a different Application Delegate class from "AppDelegate" + // you can specify it here. + UIApplication.Main (args, null, "AppDelegate"); + } + } +} diff --git a/msbuild/tests/MyTVMetalGame/Main.storyboard b/msbuild/tests/MyTVMetalGame/Main.storyboard new file mode 100644 index 0000000000..3fd9e87a9e --- /dev/null +++ b/msbuild/tests/MyTVMetalGame/Main.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msbuild/tests/MyTVMetalGame/MyTVMetalGame.csproj b/msbuild/tests/MyTVMetalGame/MyTVMetalGame.csproj new file mode 100644 index 0000000000..056c6622be --- /dev/null +++ b/msbuild/tests/MyTVMetalGame/MyTVMetalGame.csproj @@ -0,0 +1,125 @@ + + + + Debug + iPhoneSimulator + {CE09F37A-C1E9-488D-B72D-26269D735ECD} + {06FA79CB-D6CD-4721-BB4B-1BD202089C55};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Exe + MyTVMetalGame + MyTVMetalGame + Resources + + + true + full + false + bin\iPhoneSimulator\Debug + DEBUG; + prompt + 4 + iPhone Developer + true + true + true + 51092 + None + x86_64 + NSUrlSessionHandler + + + pdbonly + true + bin\iPhone\Release + prompt + 4 + iPhone Developer + true + true + true + Entitlements.plist + SdkOnly + ARM64 + NSUrlSessionHandler + + + pdbonly + true + bin\iPhoneSimulator\Release + prompt + 4 + iPhone Developer + true + None + x86_64 + NSUrlSessionHandler + + + true + full + false + bin\iPhone\Debug + DEBUG; + prompt + 4 + iPhone Developer + true + true + true + true + true + Entitlements.plist + 39926 + SdkOnly + ARM64 + NSUrlSessionHandler + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GameViewController.cs + + + + + + + \ No newline at end of file diff --git a/msbuild/tests/MyTVMetalGame/MyTVMetalGame.sln b/msbuild/tests/MyTVMetalGame/MyTVMetalGame.sln new file mode 100644 index 0000000000..6ad6a0c475 --- /dev/null +++ b/msbuild/tests/MyTVMetalGame/MyTVMetalGame.sln @@ -0,0 +1,23 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyTVMetalGame", "MyTVMetalGame.csproj", "{CE09F37A-C1E9-488D-B72D-26269D735ECD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|iPhoneSimulator = Debug|iPhoneSimulator + Release|iPhone = Release|iPhone + Release|iPhoneSimulator = Release|iPhoneSimulator + Debug|iPhone = Debug|iPhone + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CE09F37A-C1E9-488D-B72D-26269D735ECD}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator + {CE09F37A-C1E9-488D-B72D-26269D735ECD}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator + {CE09F37A-C1E9-488D-B72D-26269D735ECD}.Release|iPhone.ActiveCfg = Release|iPhone + {CE09F37A-C1E9-488D-B72D-26269D735ECD}.Release|iPhone.Build.0 = Release|iPhone + {CE09F37A-C1E9-488D-B72D-26269D735ECD}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator + {CE09F37A-C1E9-488D-B72D-26269D735ECD}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator + {CE09F37A-C1E9-488D-B72D-26269D735ECD}.Debug|iPhone.ActiveCfg = Debug|iPhone + {CE09F37A-C1E9-488D-B72D-26269D735ECD}.Debug|iPhone.Build.0 = Debug|iPhone + EndGlobalSection +EndGlobal diff --git a/msbuild/tests/MyTVMetalGame/Shaders.metal b/msbuild/tests/MyTVMetalGame/Shaders.metal new file mode 100644 index 0000000000..8784015fd0 --- /dev/null +++ b/msbuild/tests/MyTVMetalGame/Shaders.metal @@ -0,0 +1,53 @@ +#include +#include + +using namespace metal; + +// Variables in constant address space +constant float3 light_position = float3(0.0, 1.0, -1.0); +constant float4 ambient_color = float4(0.18, 0.24, 0.8, 1.0); +constant float4 diffuse_color = float4(0.4, 0.4, 1.0, 1.0); + +typedef struct +{ + float4x4 modelview_projection_matrix; + float4x4 normal_matrix; +} uniforms_t; + +typedef struct +{ + packed_float3 position; + packed_float3 normal; +} vertex_t; + +typedef struct { + float4 position [[position]]; + half4 color; +} ColorInOut; + +// Vertex shader function +vertex ColorInOut lighting_vertex(device vertex_t* vertex_array [[ buffer(0) ]], + constant uniforms_t& uniforms [[ buffer(1) ]], + unsigned int vid [[ vertex_id ]]) +{ + ColorInOut out; + + float4 in_position = float4(float3(vertex_array[vid].position), 1.0); + out.position = uniforms.modelview_projection_matrix * in_position; + + + float3 normal = vertex_array[vid].normal; + float4 eye_normal = normalize(uniforms.normal_matrix * float4(normal, 0.0)); + float n_dot_l = dot(eye_normal.rgb, normalize(light_position)); + n_dot_l = fmax(0.0, n_dot_l); + + out.color = half4(ambient_color + diffuse_color * n_dot_l); + + return out; +} + +// Fragment shader function +fragment half4 lighting_fragment(ColorInOut in [[stage_in]]) +{ + return in.color; +} diff --git a/msbuild/tests/Xamarin.iOS.Tasks.Tests/ProjectsTests/Extensions/CustomKeyboard.cs b/msbuild/tests/Xamarin.iOS.Tasks.Tests/ProjectsTests/Extensions/CustomKeyboard.cs index 05cf526aa9..1334fb2fd5 100644 --- a/msbuild/tests/Xamarin.iOS.Tasks.Tests/ProjectsTests/Extensions/CustomKeyboard.cs +++ b/msbuild/tests/Xamarin.iOS.Tasks.Tests/ProjectsTests/Extensions/CustomKeyboard.cs @@ -17,13 +17,8 @@ namespace Xamarin.iOS.Tasks { [Test] public void BasicTest () { - if (Platform == "iPhoneSimulator") { - // Note: we expect an error due to Metal not being supported on iPhoneSimulator - // Note 2: msbuild now is aware that Metal is device-only and throws an error thus this test becomes device-only for time being - //this.BuildExtension ("MyMetalGame", "MyKeyboardExtension", Platform, 1); - return; - } - + if (Platform == "iPhoneSimulator" && Environment.OSVersion.Version.Major < 19) // Environment.OSVersion = 19.* in macOS Catalina. + Assert.Ignore ("Metal support is not available in the simulator until macOS 10.15."); this.BuildExtension ("MyMetalGame", "MyKeyboardExtension", Platform, "Debug"); this.TestStoryboardC (AppBundlePath); } diff --git a/msbuild/tests/Xamarin.iOS.Tasks.Tests/ProjectsTests/TVOS/TVApp.cs b/msbuild/tests/Xamarin.iOS.Tasks.Tests/ProjectsTests/TVOS/TVApp.cs index f32bcf818c..3078c24ffd 100644 --- a/msbuild/tests/Xamarin.iOS.Tasks.Tests/ProjectsTests/TVOS/TVApp.cs +++ b/msbuild/tests/Xamarin.iOS.Tasks.Tests/ProjectsTests/TVOS/TVApp.cs @@ -1,4 +1,6 @@ -using NUnit.Framework; +using System; + +using NUnit.Framework; namespace Xamarin.iOS.Tasks { @@ -13,7 +15,9 @@ namespace Xamarin.iOS.Tasks [Test] public void BasicTest() { - BuildExtension("MyTVApp", "MyTVServicesExtension", BundlePath, Platform, "Debug"); + if (Platform == "iPhoneSimulator" && Environment.OSVersion.Version.Major < 19) // Environment.OSVersion = 19.* in macOS Catalina. + Assert.Ignore ("Metal support is not available in the simulator until macOS 10.15."); + BuildExtension ("MyTVApp", "MyTVServicesExtension", BundlePath, Platform, "Debug"); } public override string TargetFrameworkIdentifier { diff --git a/msbuild/tests/Xamarin.iOS.Tasks.Tests/ProjectsTests/TVOS/TVMetalGameTests.cs b/msbuild/tests/Xamarin.iOS.Tasks.Tests/ProjectsTests/TVOS/TVMetalGameTests.cs new file mode 100644 index 0000000000..7ad2e384d1 --- /dev/null +++ b/msbuild/tests/Xamarin.iOS.Tasks.Tests/ProjectsTests/TVOS/TVMetalGameTests.cs @@ -0,0 +1,28 @@ +using System; + +using NUnit.Framework; + +namespace Xamarin.iOS.Tasks { + [TestFixture ("iPhone")] + [TestFixture ("iPhoneSimulator")] + public class TVMetalGameTests : ProjectTest { + public TVMetalGameTests (string platform) : base (platform) + { + } + + [Test] + public void BasicTest () + { + if (Platform == "iPhoneSimulator" && Environment.OSVersion.Version.Major < 19) // Environment.OSVersion = 19.* in macOS Catalina. + Assert.Ignore ("Metal support is not available in the simulator until macOS 10.15."); + BuildProject ("MyTVMetalGame", Platform, "Debug"); + } + + public override string TargetFrameworkIdentifier { + get { + return "Xamarin.TVOS"; + } + } + } +} + diff --git a/tests/mtouch/ToolTasksBinPathTest.cs b/tests/mtouch/ToolTasksBinPathTest.cs index 781628e4e0..b119e90e3c 100644 --- a/tests/mtouch/ToolTasksBinPathTest.cs +++ b/tests/mtouch/ToolTasksBinPathTest.cs @@ -14,8 +14,10 @@ namespace Xamarin.MacDev.Tasks { public abstract class MetalTaskBase { - protected abstract string OperatingSystem { - get; + protected virtual string OperatingSystem { + get { + throw new NotImplementedException (); + } } protected abstract string DevicePlatformBinDir { @@ -82,6 +84,7 @@ namespace Xamarin.Mac.Tasks { RedirectStandardError = true, }; psi.EnvironmentVariables.Add ("DEVELOPER_DIR", Configuration.xcode_root); + psi.EnvironmentVariables.Remove ("XCODE_DEVELOPER_DIR_PATH"); // VSfM sets XCODE_DEVELOPER_DIR_PATH, which confuses the command-line tools if it doesn't match xcode-select, so just unset it. var proc = Process.Start (psi); string output = proc.StandardOutput.ReadToEnd ();