public void SetUp() { TestRuntime.AssertXcodeVersion(12, 0); device = MTLDevice.SystemDefault; // some older hardware won't have a default if (device == null) { Assert.Inconclusive("Metal is not supported"); } library = device.CreateDefaultLibrary(); if (library == null) // this happens on a simulator { Assert.Inconclusive("Could not get the functions library for the device."); } if (library.FunctionNames.Length == 0) { Assert.Inconclusive("Could not get functions for the pipeline."); } function = library.CreateFunction(library.FunctionNames [0]); pipelineState = device.CreateComputePipelineState(function, MTLPipelineOption.ArgumentInfo, out MTLComputePipelineReflection reflection, out NSError error); if (error != null) { Assert.Inconclusive($"Could not create pipeline {error}"); } descriptor = MTLIntersectionFunctionTableDescriptor.Create(); functionTable = pipelineState.CreateIntersectionFunctionTable(descriptor); }
bool PrepareCompute() { NSError error; // Create a compute kernel function IMTLFunction function = shaderLibrary.CreateFunction("grayscale"); if (function == null) { Console.WriteLine("ERROR: Failed creating a new function!"); return(false); } // Create a compute kernel kernel = device.CreateComputePipelineState(function, out error); if (kernel == null) { Console.WriteLine("ERROR: Failed creating a compute kernel: %@", error.Description); return(false); } MTLTextureDescriptor texDesc = MTLTextureDescriptor.CreateTexture2DDescriptor(MTLPixelFormat.RGBA8Unorm, (nuint)size.Width, (nuint)size.Height, false); if (texDesc == null) { Console.WriteLine("ERROR: Failed creating a texture 2d descriptor with RGBA unnormalized pixel format!"); return(false); } outTexture = device.CreateTexture(texDesc); if (outTexture == null) { Console.WriteLine("ERROR: Failed creating an output 2d texture!"); return(false); } // Set the compute kernel's workgroup size and count workgroupSize = new MTLSize(1, 1, 1); localCount = new MTLSize((nint)size.Width, (nint)size.Height, 1); return(true); }
public MetalClothSimulator(IMTLDevice device) { this.device = device; this.commandQueue = this.device.CreateCommandQueue(); this.defaultLibrary = this.device.CreateDefaultLibrary(); this.functionClothSim = this.defaultLibrary.CreateFunction("updateVertex"); this.functionNormalUpdate = this.defaultLibrary.CreateFunction("updateNormal"); this.functionNormalSmooth = this.defaultLibrary.CreateFunction("smoothNormal"); this.pipelineStateClothSim = this.device.CreateComputePipelineState(this.functionClothSim, out NSError pipelineStateClothSimError); this.pipelineStateNormalUpdate = this.device.CreateComputePipelineState(this.functionNormalUpdate, out NSError pipelineStateNormalUpdateError); this.pipelineStateNormalSmooth = this.device.CreateComputePipelineState(this.functionNormalSmooth, out NSError pipelineStateNormalSmoothError); if (pipelineStateClothSimError != null || pipelineStateNormalUpdateError != null || pipelineStateNormalSmoothError != null) { throw new Exception("error"); } }
public override void ViewDidLoad() { base.ViewDidLoad(); // Set the view to use the default device device = MTLDevice.SystemDefault; if (device == null) { Console.WriteLine("Metal is not supported on this device"); View = new NSView(View.Frame); } // Create a new command queue commandQueue = device.CreateCommandQueue(); NSError error; // Setup view view = (MTKView)View; view.Delegate = this; view.Device = device; view.SampleCount = 1; view.DepthStencilPixelFormat = MTLPixelFormat.Depth32Float_Stencil8; view.ColorPixelFormat = MTLPixelFormat.BGRA8Unorm; view.PreferredFramesPerSecond = 60; view.ClearColor = new MTLClearColor(0, 0, 0, 1.0f); // Functions var source = System.IO.File.ReadAllText("Triangle.metal"); MTLCompileOptions compileOptions = new MTLCompileOptions() { LanguageVersion = MTLLanguageVersion.v2_0, }; IMTLLibrary customLibrary = device.CreateLibrary(source, compileOptions, out error); IMTLFunction kernelFunction = customLibrary.CreateFunction("tessellation_kernel_triangle"); IMTLFunction vertexFunction = customLibrary.CreateFunction("tessellation_vertex_triangle"); IMTLFunction fragmentFunction = customLibrary.CreateFunction("tessellation_fragment"); // Create a vertex descriptor MTLVertexDescriptor vertexDescriptor = new MTLVertexDescriptor(); vertexDescriptor.Attributes[0].Format = MTLVertexFormat.Float4; vertexDescriptor.Attributes[0].BufferIndex = 0; vertexDescriptor.Attributes[0].Offset = 0; vertexDescriptor.Layouts[0].Stride = 4 * sizeof(float); vertexDescriptor.Layouts[0].StepRate = 1; vertexDescriptor.Layouts[0].StepFunction = MTLVertexStepFunction.PerPatchControlPoint; // Create RenderPipeline var renderPipelineStateDescriptor = new MTLRenderPipelineDescriptor { SampleCount = view.SampleCount, VertexFunction = vertexFunction, FragmentFunction = fragmentFunction, VertexDescriptor = vertexDescriptor, DepthAttachmentPixelFormat = view.DepthStencilPixelFormat, StencilAttachmentPixelFormat = view.DepthStencilPixelFormat, MaxTessellationFactor = 16, IsTessellationFactorScaleEnabled = false, TessellationFactorFormat = MTLTessellationFactorFormat.Half, TessellationControlPointIndexType = MTLTessellationControlPointIndexType.None, TessellationFactorStepFunction = MTLTessellationFactorStepFunction.Constant, TessellationOutputWindingOrder = MTLWinding.Clockwise, TessellationPartitionMode = MTLTessellationPartitionMode.FractionalEven, }; renderPipelineStateDescriptor.ColorAttachments[0].PixelFormat = view.ColorPixelFormat; renderPipelineState = device.CreateRenderPipelineState(renderPipelineStateDescriptor, out error); if (renderPipelineState == null) { Console.WriteLine("Failed to created pipeline state, error {0}", error); } MTLDepthStencilDescriptor depthStateDesc = new MTLDepthStencilDescriptor { DepthCompareFunction = MTLCompareFunction.Less, DepthWriteEnabled = true }; depthState = device.CreateDepthStencilState(depthStateDesc); computePipelineState = device.CreateComputePipelineState(kernelFunction, out error); // Buffers tessellationFactorsBuffer = device.CreateBuffer(256, MTLResourceOptions.StorageModePrivate); tessellationFactorsBuffer.Label = "Tessellation Factors"; controlPointsBuffer = device.CreateBuffer(controlPointPositionsTriangle, MTLResourceOptions.StorageModeManaged); controlPointsBuffer.Label = "Control Points Triangle"; }
bool PrepareCompute () { NSError error; // Create a compute kernel function IMTLFunction function = shaderLibrary.CreateFunction ("grayscale"); if(function == null) { Console.WriteLine ("ERROR: Failed creating a new function!"); return false; } // Create a compute kernel kernel = device.CreateComputePipelineState (function, out error); if(kernel == null) { Console.WriteLine ("ERROR: Failed creating a compute kernel: %@", error.Description); return false; } MTLTextureDescriptor texDesc = MTLTextureDescriptor.CreateTexture2DDescriptor (MTLPixelFormat.RGBA8Unorm, (nuint)size.Width, (nuint)size.Height, false); if(texDesc == null) { Console.WriteLine ("ERROR: Failed creating a texture 2d descriptor with RGBA unnormalized pixel format!"); return false; } outTexture = device.CreateTexture (texDesc); if(outTexture == null) { Console.WriteLine ("ERROR: Failed creating an output 2d texture!"); return false; } // Set the compute kernel's workgroup size and count workgroupSize = new MTLSize (1, 1, 1); localCount = new MTLSize ((nint)size.Width, (nint)size.Height, 1); return true; }
protected virtual void Dispose(bool disposing) { if (!this.disposed) { if (disposing) { if (this.commandQueue != null) { this.commandQueue.Dispose(); this.commandQueue = null; } if (this.defaultLibrary != null) { this.defaultLibrary.Dispose(); this.defaultLibrary = null; } if (this.functionClothSim != null) { this.functionClothSim.Dispose(); this.functionClothSim = null; } if (this.functionNormalUpdate != null) { this.functionNormalUpdate.Dispose(); this.functionNormalUpdate = null; } if (this.functionNormalSmooth != null) { this.functionNormalSmooth.Dispose(); this.functionNormalSmooth = null; } if (this.pipelineStateClothSim != null) { this.pipelineStateClothSim.Dispose(); this.pipelineStateClothSim = null; } if (this.pipelineStateNormalUpdate != null) { this.pipelineStateNormalUpdate.Dispose(); this.pipelineStateNormalUpdate = null; } if (this.pipelineStateNormalSmooth != null) { this.pipelineStateNormalSmooth.Dispose(); this.pipelineStateNormalSmooth = null; } foreach (var item in this.clothData) { item.ClothNode.RemoveFromParentNode(); item.Dispose(); } this.clothData.Clear(); } this.disposed = true; } }