[msbuild] Add support for Metal in the simulator. Fixes #7392. (#7983) (#7991)

* [msbuild] Provide the correct value for the operating system for tvOS and watchOS to a few tasks. Fixes #6200. (#7226)

The problem with #6200 was that we'd pass -mios-version-min=x.y to the metal
tool even for tvOS apps. This fixes it so that now pass -mtvos-version-min.

Fixes https://github.com/xamarin/xamarin-macios/issues/6200.

* [msbuild] Add support for Metal in the simulator. Fixes #7392. (#7983)
This commit is contained in:
Rolf Bjarne Kvinge 2020-02-28 19:59:03 +01:00 коммит произвёл GitHub
Родитель fe451491f6
Коммит ad15106af4
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
46 изменённых файлов: 1390 добавлений и 39 удалений

Просмотреть файл

@ -4,8 +4,5 @@ namespace Xamarin.Mac.Tasks
{
public class CompileSceneKitAssets : CompileSceneKitAssetsTaskBase
{
protected override string OperatingSystem {
get { return "osx"; }
}
}
}

Просмотреть файл

@ -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; }

Просмотреть файл

@ -4,8 +4,5 @@ namespace Xamarin.Mac.Tasks
{
public class ScnTool : ScnToolTaskBase
{
protected override string OperatingSystem {
get { return "osx"; }
}
}
}

Просмотреть файл

@ -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"

Просмотреть файл

@ -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));
}
}
}
}

Просмотреть файл

@ -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 {

Просмотреть файл

@ -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 {

Просмотреть файл

@ -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 {

Просмотреть файл

@ -2,8 +2,5 @@
{
public abstract class CompileSceneKitAssetsTaskBase : Xamarin.MacDev.Tasks.CompileSceneKitAssetsTaskBase
{
protected override string OperatingSystem {
get { return "ios"; }
}
}
}

Просмотреть файл

@ -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; }
}

Просмотреть файл

@ -2,8 +2,5 @@
{
public abstract class ScnToolTaskBase : Xamarin.MacDev.Tasks.ScnToolTaskBase
{
protected override string OperatingSystem {
get { return "ios"; }
}
}
}

Просмотреть файл

@ -595,16 +595,16 @@ Copyright (C) 2013-2016 Xamarin. All rights reserved.
</Target>
<Target Name="_SmeltMetal" Condition="'$(_CanOutputAppBundle)' == 'true' And '@(Metal)' != ''" DependsOnTargets="_DetectSdkLocations">
<Error Condition="'$(ComputedPlatform)' == 'iPhoneSimulator'" Text="The iOS Simulator does not support metal. Build for a device instead."/>
<Metal
SessionId="$(BuildSessionId)"
Condition="'$(IsMacEnabled)' == 'true' and '%(Metal.Identity)' != ''"
IntermediateOutputPath="$(DeviceSpecificIntermediateOutputPath)"
AppManifest="$(_AppManifest)"
ProjectDir="$(MSBuildProjectDirectory)"
TargetFrameworkIdentifier="$(TargetFrameworkIdentifier)"
ResourcePrefix="$(IPhoneResourcePrefix)"
SdkDevPath="$(_SdkDevPath)"
SdkIsSimulator="$(_SdkIsSimulator)"
SdkRoot="$(_SdkRoot)"
SdkVersion="$(MtouchSdkVersion)"
SourceFile="@(Metal)">
@ -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)"

Просмотреть файл

@ -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";

Просмотреть файл

@ -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

Просмотреть файл

@ -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.
}
}
}

Просмотреть файл

@ -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"
}
}

Просмотреть файл

@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Просмотреть файл

@ -0,0 +1,17 @@
{
"layers" : [
{
"filename" : "Front.imagestacklayer"
},
{
"filename" : "Middle.imagestacklayer"
},
{
"filename" : "Back.imagestacklayer"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Просмотреть файл

@ -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"
}
}

Просмотреть файл

@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Просмотреть файл

@ -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"
}
}

Просмотреть файл

@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Просмотреть файл

@ -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"
}
}

Просмотреть файл

@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Просмотреть файл

@ -0,0 +1,17 @@
{
"layers" : [
{
"filename" : "Front.imagestacklayer"
},
{
"filename" : "Middle.imagestacklayer"
},
{
"filename" : "Back.imagestacklayer"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Просмотреть файл

@ -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"
}
}

Просмотреть файл

@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Просмотреть файл

@ -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"
}
}

Просмотреть файл

@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Просмотреть файл

@ -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"
}
}

Просмотреть файл

@ -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"
}
}

Просмотреть файл

@ -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"
}
}

Просмотреть файл

@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Просмотреть файл

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
</dict>
</plist>

Просмотреть файл

@ -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<float> (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;
}
}
}

11
msbuild/tests/MyTVMetalGame/GameViewController.designer.cs сгенерированный Normal file
Просмотреть файл

@ -0,0 +1,11 @@
using Foundation;
using System.CodeDom.Compiler;
namespace MyTVMetalGame {
[Register ("GameViewController")]
partial class GameViewController {
void ReleaseDesignerOutlets ()
{
}
}
}

Просмотреть файл

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDisplayName</key>
<string>MyTVMetalGame</string>
<key>CFBundleName</key>
<string>MyTVMetalGame</string>
<key>CFBundleIdentifier</key>
<string>com.xamarin.MyTVMetalGame</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>13.0</string>
<key>UIDeviceFamily</key>
<array>
<integer>3</integer>
</array>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>arm64</string>
</array>
<key>GCSupportedGameControllers</key>
<array>
<dict>
<key>ProfileName</key>
<string>ExtendedGamepad</string>
</dict>
<dict>
<key>ProfileName</key>
<string>MicroGamepad</string>
</dict>
</array>
<key>GCSupportsControllerUserInteraction</key>
<true/>
<key>XSAppIconAssets</key>
<string>Assets.xcassets/App Icon &amp; Top Shelf Image.brandassets</string>
<key>XSLaunchImageAssets</key>
<string>Assets.xcassets/LaunchImages.launchimage</string>
</dict>
</plist>

Просмотреть файл

@ -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");
}
}
}

Просмотреть файл

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6211" systemVersion="14A298i" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BV1-FR-VrT">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6204"/>
</dependencies>
<scenes>
<!--Game View Controller-->
<scene sceneID="tXr-a1-R10">
<objects>
<viewController id="BV1-FR-VrT" customClass="GameViewController" customModuleProvider="" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="8aa-yV-Osq"/>
<viewControllerLayoutGuide type="bottom" id="qHh-Mt-9TT"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="3se-qz-xqx">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="SZV-WD-TEh" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>

Просмотреть файл

@ -0,0 +1,125 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">iPhoneSimulator</Platform>
<ProjectGuid>{CE09F37A-C1E9-488D-B72D-26269D735ECD}</ProjectGuid>
<ProjectTypeGuids>{06FA79CB-D6CD-4721-BB4B-1BD202089C55};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<OutputType>Exe</OutputType>
<RootNamespace>MyTVMetalGame</RootNamespace>
<AssemblyName>MyTVMetalGame</AssemblyName>
<IPhoneResourcePrefix>Resources</IPhoneResourcePrefix>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhoneSimulator' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\iPhoneSimulator\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CodesignKey>iPhone Developer</CodesignKey>
<MtouchDebug>true</MtouchDebug>
<MtouchNoSymbolStrip>true</MtouchNoSymbolStrip>
<MtouchFastDev>true</MtouchFastDev>
<IOSDebuggerPort>51092</IOSDebuggerPort>
<MtouchLink>None</MtouchLink>
<MtouchArch>x86_64</MtouchArch>
<MtouchHttpClientHandler>NSUrlSessionHandler</MtouchHttpClientHandler>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhone' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\iPhone\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CodesignKey>iPhone Developer</CodesignKey>
<MtouchUseLlvm>true</MtouchUseLlvm>
<MtouchFloat32>true</MtouchFloat32>
<MtouchEnableBitcode>true</MtouchEnableBitcode>
<CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
<MtouchLink>SdkOnly</MtouchLink>
<MtouchArch>ARM64</MtouchArch>
<MtouchHttpClientHandler>NSUrlSessionHandler</MtouchHttpClientHandler>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhoneSimulator' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\iPhoneSimulator\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CodesignKey>iPhone Developer</CodesignKey>
<MtouchNoSymbolStrip>true</MtouchNoSymbolStrip>
<MtouchLink>None</MtouchLink>
<MtouchArch>x86_64</MtouchArch>
<MtouchHttpClientHandler>NSUrlSessionHandler</MtouchHttpClientHandler>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhone' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\iPhone\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<CodesignKey>iPhone Developer</CodesignKey>
<DeviceSpecificBuild>true</DeviceSpecificBuild>
<MtouchDebug>true</MtouchDebug>
<MtouchNoSymbolStrip>true</MtouchNoSymbolStrip>
<MtouchFastDev>true</MtouchFastDev>
<MtouchFloat32>true</MtouchFloat32>
<CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
<IOSDebuggerPort>39926</IOSDebuggerPort>
<MtouchLink>SdkOnly</MtouchLink>
<MtouchArch>ARM64</MtouchArch>
<MtouchHttpClientHandler>NSUrlSessionHandler</MtouchHttpClientHandler>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Xml" />
<Reference Include="System.Core" />
<Reference Include="Xamarin.TVOS" />
</ItemGroup>
<ItemGroup>
<ImageAsset Include="Assets.xcassets\App Icon &amp; Top Shelf Image.brandassets\Contents.json" />
<ImageAsset Include="Assets.xcassets\App Icon &amp; Top Shelf Image.brandassets\App Icon - Large.imagestack\Contents.json" />
<ImageAsset Include="Assets.xcassets\App Icon &amp; Top Shelf Image.brandassets\App Icon - Large.imagestack\Back.imagestacklayer\Contents.json" />
<ImageAsset Include="Assets.xcassets\App Icon &amp; Top Shelf Image.brandassets\App Icon - Large.imagestack\Back.imagestacklayer\Content.imageset\Contents.json" />
<ImageAsset Include="Assets.xcassets\App Icon &amp; Top Shelf Image.brandassets\App Icon - Large.imagestack\Front.imagestacklayer\Contents.json" />
<ImageAsset Include="Assets.xcassets\App Icon &amp; Top Shelf Image.brandassets\App Icon - Large.imagestack\Front.imagestacklayer\Content.imageset\Contents.json" />
<ImageAsset Include="Assets.xcassets\App Icon &amp; Top Shelf Image.brandassets\App Icon - Large.imagestack\Middle.imagestacklayer\Contents.json" />
<ImageAsset Include="Assets.xcassets\App Icon &amp; Top Shelf Image.brandassets\App Icon - Large.imagestack\Middle.imagestacklayer\Content.imageset\Contents.json" />
<ImageAsset Include="Assets.xcassets\App Icon &amp; Top Shelf Image.brandassets\App Icon - Small.imagestack\Contents.json" />
<ImageAsset Include="Assets.xcassets\App Icon &amp; Top Shelf Image.brandassets\App Icon - Small.imagestack\Back.imagestacklayer\Contents.json" />
<ImageAsset Include="Assets.xcassets\App Icon &amp; Top Shelf Image.brandassets\App Icon - Small.imagestack\Back.imagestacklayer\Content.imageset\Contents.json" />
<ImageAsset Include="Assets.xcassets\App Icon &amp; Top Shelf Image.brandassets\App Icon - Small.imagestack\Front.imagestacklayer\Contents.json" />
<ImageAsset Include="Assets.xcassets\App Icon &amp; Top Shelf Image.brandassets\App Icon - Small.imagestack\Front.imagestacklayer\Content.imageset\Contents.json" />
<ImageAsset Include="Assets.xcassets\App Icon &amp; Top Shelf Image.brandassets\App Icon - Small.imagestack\Middle.imagestacklayer\Contents.json" />
<ImageAsset Include="Assets.xcassets\App Icon &amp; Top Shelf Image.brandassets\App Icon - Small.imagestack\Middle.imagestacklayer\Content.imageset\Contents.json" />
<ImageAsset Include="Assets.xcassets\App Icon &amp; Top Shelf Image.brandassets\Top Shelf Image Wide.imageset\Contents.json" />
<ImageAsset Include="Assets.xcassets\App Icon &amp; Top Shelf Image.brandassets\Top Shelf Image.imageset\Contents.json" />
<ImageAsset Include="Assets.xcassets\Contents.json" />
</ItemGroup>
<ItemGroup>
<Folder Include="Resources\" />
</ItemGroup>
<ItemGroup>
<Metal Include="Shaders.metal" />
</ItemGroup>
<ItemGroup>
<None Include="Info.plist" />
<None Include="Entitlements.plist" />
</ItemGroup>
<ItemGroup>
<Compile Include="Main.cs" />
<Compile Include="AppDelegate.cs" />
<Compile Include="GameViewController.cs" />
<Compile Include="GameViewController.designer.cs">
<DependentUpon>GameViewController.cs</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<InterfaceDefinition Include="Main.storyboard" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\TVOS\Xamarin.TVOS.CSharp.targets" />
</Project>

Просмотреть файл

@ -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

Просмотреть файл

@ -0,0 +1,53 @@
#include <metal_stdlib>
#include <simd/simd.h>
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;
}

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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 {

Просмотреть файл

@ -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";
}
}
}
}

Просмотреть файл

@ -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 ();