Ipad 在iOS设备上设置Swift 3中的金属

Ipad 在iOS设备上设置Swift 3中的金属,ipad,swift3,metal,metalkit,Ipad,Swift3,Metal,Metalkit,我一直在尝试将苹果的项目转换为在iPad Air 3上使用swift 3,但迄今为止都没有成功。令人沮丧的是,该项目附带了一个iOS实现(用Objective编写,还有一个swift游乐场),但没有swift 3实现 我已经获得了要编译的代码,但由于以下错误未能在我的iPad上运行: 2017-05-14 14:25:54.268400-0700 MetalBasicTessellation[2436:570250] -[MTLRenderPipelineDescriptorInternal v

我一直在尝试将苹果的项目转换为在iPad Air 3上使用swift 3,但迄今为止都没有成功。令人沮丧的是,该项目附带了一个iOS实现(用Objective编写,还有一个swift游乐场),但没有swift 3实现

我已经获得了要编译的代码,但由于以下错误未能在我的iPad上运行:

2017-05-14 14:25:54.268400-0700 MetalBasicTessellation[2436:570250] -[MTLRenderPipelineDescriptorInternal validateWithDevice:], line 1728: error 'tessellation is only supported on MTLFeatureSet_iOS_GPUFamily3_v1 and later'
我很确定iPad Air 2是兼容的,但我感觉错误是由于配置不正确的MetalKitView造成的。我已经从项目的objective-c和游乐场文件中逆向工程了我所能做的,但我已经尽我目前的专业知识所能理解了

//
//  ViewController.swift
//  MetalBasicTessellation
//
//  Created by vladimir sierra on 5/10/17.
//  
//

import UIKit
import Metal
import MetalKit

class ViewController: UIViewController {

  @IBOutlet weak var mtkView: MTKView!

  // Seven steps required to set up metal for rendering:

  // 1. Create a MTLDevice
  // 2. Create a CAMetalLayer
  // 3. Create a Vertex Buffer

  // 4. Create a Vertex Shader
  // 5. Create a Fragment Shader

  // 6. Create a Render Pipeline
  // 7. Create a Command Queue

  var device: MTLDevice! // to be initialized in viewDidLoad
  //var metalLayer: CAMetalLayer! // to be initialized in viewDidLoad
  var vertexBuffer: MTLBuffer! // to be initialized in viewDidLoad
  var library: MTLLibrary!

  // once we create a vertex and fragment shader, we combine them in an object called render pipeline. In Metal the shaders are precompiled, and the render pipeline configuration is compiled after you first set it up. This makes everything extremely efficient

  var renderPipeline: MTLRenderPipelineState! // to be initialized in viewDidLoad
  var commandQueue: MTLCommandQueue! // to be initialized in viewDidLoad

  //var timer: CADisplayLink! // function to be called every time the device screen refreshes so we can redraw the screen



  override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    /*
    if let window = view.window {
      let scale = window.screen.nativeScale // (2 for iPhone 5s, 6 and iPads;  3 for iPhone 6 Plus)
      let layerSize = view.bounds.size
      // apply the scale to increase the drawable texture size.
      view.contentScaleFactor = scale
      //metalLayer.frame = CGRect(x: 0, y: 0, width: layerSize.width, height: layerSize.height)
      //metalLayer.drawableSize = CGSize(width: layerSize.width * scale, height: layerSize.height * scale)
    } */
  }

  override func viewDidLoad() {
    super.viewDidLoad()

    device = MTLCreateSystemDefaultDevice() // returns a reference to the default MTLDevice

    //device.supportsFeatureSet(MTLFeatureSet_iOS_GPUFamily3_v2)



    // set up layer to display metal content
    //metalLayer = CAMetalLayer()          // initialize metalLayer
    //metalLayer.device = device           // device the layer should use
    //metalLayer.pixelFormat = .bgra8Unorm // normalized 8 bit rgba
    //metalLayer.framebufferOnly = true    // set to true for performance issues
    //view.layer.addSublayer(metalLayer)   // add sublayer to main view's layer

    // precompile custom metal functions

    let defaultLibrary = device.newDefaultLibrary()! // MTLLibrary object with precompiled shaders


    let fragmentProgram = defaultLibrary.makeFunction(name: "tessellation_fragment")
    let vertexProgram = defaultLibrary.makeFunction(name: "tessellation_vertex_triangle")

    // Setup Compute Pipeline
    let kernelFunction = defaultLibrary.makeFunction(name: "tessellation_kernel_triangle")
    var computePipeline: MTLComputePipelineState?
    do {
      computePipeline = try device.makeComputePipelineState(function: kernelFunction!)
    } catch let error as NSError {
      print("compute pipeline error: " + error.description)
    }

    // Setup Vertex Descriptor
    let vertexDescriptor = MTLVertexDescriptor()
    vertexDescriptor.attributes[0].format = .float4
    vertexDescriptor.attributes[0].offset = 0
    vertexDescriptor.attributes[0].bufferIndex = 0;
    vertexDescriptor.layouts[0].stepFunction = .perPatchControlPoint
    vertexDescriptor.layouts[0].stepRate = 1
    vertexDescriptor.layouts[0].stride = 4*MemoryLayout<Float>.size

    // Setup Render Pipeline
    let renderPipelineDescriptor = MTLRenderPipelineDescriptor()
    renderPipelineDescriptor.vertexDescriptor = vertexDescriptor
    //renderPipelineDescriptor.fragmentFunction = defaultLibrary.makeFunction(name: "tessellation_fragment")
    renderPipelineDescriptor.fragmentFunction = fragmentProgram
    //renderPipelineDescriptor.vertexFunction = defaultLibrary.makeFunction(name: "tessellation_vertex_triangle")
    renderPipelineDescriptor.vertexFunction = vertexProgram

    //renderPipelineDescriptor.colorAttachments[0].pixelFormat = .bgra8Unorm // normalized 8 bit rgba
    renderPipelineDescriptor.colorAttachments[0].pixelFormat = mtkView.colorPixelFormat

    renderPipelineDescriptor.isTessellationFactorScaleEnabled = false
    renderPipelineDescriptor.tessellationFactorFormat = .half
    renderPipelineDescriptor.tessellationControlPointIndexType = .none
    renderPipelineDescriptor.tessellationFactorStepFunction = .constant
    renderPipelineDescriptor.tessellationOutputWindingOrder = .clockwise
    renderPipelineDescriptor.tessellationPartitionMode = .fractionalEven
    renderPipelineDescriptor.maxTessellationFactor = 64;

    // Compile renderPipeline
    do {
      renderPipeline = try device.makeRenderPipelineState(descriptor: renderPipelineDescriptor)
    } catch let error as NSError {
      print("render pipeline error: " + error.description)
    }

    // Setup Buffers
    let tessellationFactorsBuffer = device.makeBuffer(length: 256, options: MTLResourceOptions.storageModePrivate)
    let controlPointPositions: [Float] = [
      -0.8, -0.8, 0.0, 1.0,   // lower-left
      0.0,  0.8, 0.0, 1.0,   // upper-middle
      0.8, -0.8, 0.0, 1.0,   // lower-right
    ]
    let controlPointsBuffer = device.makeBuffer(bytes: controlPointPositions, length:256 , options: [])

    // Tessellation Pass
    let commandBuffer = commandQueue.makeCommandBuffer()

    let computeCommandEncoder = commandBuffer.makeComputeCommandEncoder()
    computeCommandEncoder.setComputePipelineState(computePipeline!)

    let edgeFactor: [Float] = [16.0]
    let insideFactor: [Float] = [8.0]
    computeCommandEncoder.setBytes(edgeFactor, length: MemoryLayout<Float>.size, at: 0)
    computeCommandEncoder.setBytes(insideFactor, length: MemoryLayout<Float>.size, at: 1)
    computeCommandEncoder.setBuffer(tessellationFactorsBuffer, offset: 0, at: 2)
    computeCommandEncoder.dispatchThreadgroups(MTLSizeMake(1, 1, 1), threadsPerThreadgroup: MTLSizeMake(1, 1, 1))
    computeCommandEncoder.endEncoding()

    let renderPassDescriptor = mtkView.currentRenderPassDescriptor
    let renderCommandEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor!)
    renderCommandEncoder.setRenderPipelineState(renderPipeline!)
    renderCommandEncoder.setVertexBuffer(controlPointsBuffer, offset: 0, at: 0)
    renderCommandEncoder.setTriangleFillMode(.lines)
    renderCommandEncoder.setTessellationFactorBuffer(tessellationFactorsBuffer, offset: 0, instanceStride: 0)
    renderCommandEncoder.drawPatches(numberOfPatchControlPoints: 3, patchStart: 0, patchCount: 1, patchIndexBuffer: nil, patchIndexBufferOffset: 0, instanceCount: 1, baseInstance: 0)
    renderCommandEncoder.endEncoding()

    commandBuffer.present(mtkView.currentDrawable!)
    commandBuffer.commit()
    commandBuffer.waitUntilCompleted()
    /*
    // finally create an ordered list of commands forthe GPU to execute
    commandQueue = device.makeCommandQueue()

    timer = CADisplayLink(target: self, selector: #selector(ViewController.gameloop)) // call gameloop every time the screen refreshes
    timer.add(to: RunLoop.main, forMode: RunLoopMode.defaultRunLoopMode)

    */



  }

  override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
  }

  /*
  func render() {
    guard let drawable = metalLayer?.nextDrawable() else { return } // returns the texture to draw into in order for something to appear on the screen
    //objectToDraw.render(commandQueue: commandQueue, renderPipeline: renderPipeline, drawable: drawable, clearColor: nil)
  }

  // this is the routine that gets run every time the screen refreshes
  func gameloop() {
    autoreleasepool {
      self.render()
    }
  } */


}
//
//ViewController.swift
//金属基振动
//
//弗拉基米尔·塞拉于2017年5月10日创作。
//  
//
导入UIKit
进口金属
进口金属套件
类ViewController:UIViewController{
@IBV弱变量mtkView:mtkView!
//设置渲染金属所需的七个步骤:
//1.创建MTL设备
//2.创建CametLayer
//3.创建顶点缓冲区
//4.创建顶点着色器
//5.创建片段着色器
//6.创建渲染管道
//7.创建命令队列
var设备:MTLDevice!//要在viewDidLoad中初始化
//var metalLayer:CAMetalLayer!//将在viewDidLoad中初始化
var vertexBuffer:MTLBuffer!//要在viewDidLoad中初始化
var库:MTLLibrary!
//创建顶点和片段着色器后,我们将它们组合到一个名为“渲染管道”的对象中。在Metal中,着色器是预编译的,渲染管道配置是在您首次设置后编译的。这使得一切都非常高效
var renderPipeline:MTLRenderPipelineState!//要在viewDidLoad中初始化
var commandQueue:MTLCommandQueue!//要在viewDidLoad中初始化
//var timer:CADisplayLink!//每次设备屏幕刷新时调用的函数,以便我们可以重新绘制屏幕
重写func viewdilayoutsubviews(){
super.viewDidLayoutSubviews()
/*
如果let window=view.window{
让scale=window.screen.nativeScale/(2个用于iPhone 5s、6和iPad;3个用于iPhone 6 Plus)
让layerSize=view.bounds.size
//应用比例以增加可绘制纹理大小。
view.contentScaleFactor=scale
//metalLayer.frame=CGRect(x:0,y:0,宽度:layerSize.width,高度:layerSize.height)
//metalLayer.drawableSize=CGSize(宽度:layerSize.width*比例,高度:layerSize.height*比例)
} */
}
重写func viewDidLoad(){
super.viewDidLoad()
device=MTLCreateSystemDefaultDevice()//返回对默认MTL设备的引用
//设备支持功能集(MTLFeatureSet\u iOS\u GPUFamily3\u v2)
//设置图层以显示金属内容
//metalLayer=CametLayer()//初始化metalLayer
//metalLayer.device=设备//该层应使用的设备
//metalayer.pixelFormat=.bgra8Unorm//标准化8位rgba
//metalLayer.framebufferOnly=true//设置为true以解决性能问题
//view.layer.addSublayer(metalayer)//将子层添加到主视图的层
//预编译自定义金属函数
让defaultLibrary=device.newDefaultLibrary()!//带有预编译着色器的MTLLibrary对象
让fragmentProgram=defaultLibrary.makeFunction(名称:“镶嵌_片段”)
让vertexProgram=defaultLibrary.makeFunction(名称:“细分\顶点\三角形”)
//设置计算管道
让kernelFunction=defaultLibrary.makeFunction(名称:“镶嵌\内核\三角形”)
var computePipeline:MTLComputePipelineState?
做{
computePipeline=try device.makeComputePipelineState(函数:kernelFunction!)
}将let错误捕获为NSError{
打印(“计算管道错误:+错误。说明”)
}
//设置顶点描述符
让vertexDescriptor=MTLVertexDescriptor()
vertexDescriptor.attributes[0]。格式=.float4
vertexDescriptor.attributes[0]。偏移量=0
vertexDescriptor.attributes[0].bufferIndex=0;
vertexDescriptor.layouts[0]。stepFunction=.perPatchControlPoint
vertexDescriptor.layouts[0]。步长=1
vertexDescriptor.layouts[0]。步长=4*MemoryLayout.size
//设置渲染管道
让renderPipelineDescriptor=MTLRenderPipelineDescriptor()
renderPipelineDescriptor.vertexDescriptor=vertexDescriptor
//renderPipelineDescriptor.fragmentFunction=defaultLibrary.makeFunction(名称:“镶嵌_片段”)
renderPipelineDescriptor.fragmentFunction=fragmentProgram
//renderPipelineDescriptor.vertexFunction=defaultLibrary.makeFunction(名称:“镶嵌\顶点\三角形”)
renderPipelineDescriptor.vertexFunction=vertexProgram
//renderPipelineDescriptor.colorAttachments[0]。pixelFormat=.bgra8Unorm//标准化8位rgba
renderPipelineDescriptor.colorAttachments[0]。pixelFormat=mtkView.colorPixelFormat
renderPipelineDescriptor.IsTestInstallationFactorScaleEnabled=false
renderPipelineDescriptor.tessellationFactorFormat=.half
renderPipelineDescriptor.tessellationControlPointIndexType=.none
renderPipelineDescriptor.tessellationFactorStepFunction=.constant
renderPipelineDescriptor.tessellationOutputWindingOrder=
renderPipelineDescriptor.tessellationPartitionMode=.Fractileven
renderPipelineDescriptor.maxTessellationFactor=64;
//编译渲染管线
做{
renderPipeline=try device.makeRenderPipelineState(描述符:renderPipelineDescriptor)
}将let错误捕获为NSError{
打印(“渲染管道错误:+错误。说明”)
}
//设置缓冲区
让tessellationFactorsBuffer=device.makeBuffer(长度:256,选项:MTLResourceOptions.storageModePrivate)
让controlPointPositions:[浮动]=[
-0.8,-0.8,0.0,1.0,//左下角
0.0,0.8,0.0,1.0,//中上部
0.8,-0.8,0.0,1.0,//较低的ri