[MetalKit]7-Using-MetalKit-part-6使用MetalKit6

蘋果API搬運工發表於2017-12-14

本系列文章是對 metalkit.org 上面MetalKit內容的全面翻譯和學習.

MetalKit系統文章目錄


讓我們來看看新的MetalKit框架和以前的Metal框架有什麼不同.它們是同時共存的,但是,MetalKit引入了一些強勁的新特性,比如:

  • 紋理更容易載入(只需幾行程式碼就可以非同步載入).
  • Model I/O網格mash和Metal緩衝器buffer之間的高效資料傳輸.
  • MTKView-一個方便的Metal-aware Metal認識的檢視(我們稍後會深入研究它).

我將從回顧第一篇中的程式開始:

import MetalKit

class MetalView: MTKView {

    override func drawRect(dirtyRect: NSRect) {
        super.drawRect(dirtyRect)
        render()
    }
 
    func render() {
        device = MTLCreateSystemDefaultDevice()
        if let rpd = currentRenderPassDescriptor, drawable = currentDrawable {
            rpd.colorAttachments[0].clearColor = MTLClearColorMake(0, 0.5, 0.5, 1.0)
            let command_buffer = device!.newCommandQueue().commandBuffer()
            let command_encoder = command_buffer.renderCommandEncoderWithDescriptor(rpd)
            command_encoder.endEncoding()
            command_buffer.presentDrawable(drawable)
            command_buffer.commit()
        }
    }
}
複製程式碼

就是這樣!簡單優雅清理裝置的背景色.現在我們切換到Metal框架,它並沒有MTKView,所以我們必須繼承於NSView(iOS上是UIView).

import Cocoa

class MetalView: NSView {
複製程式碼

你會直接注意到一些錯誤提示,顯示下面的屬性預設情況下沒有提供給我們:

  • a device裝置
  • a drawable繪製資源
  • a render pass descriptor渲染通道描述符

讓我們修復這些錯誤.首先,因為NSView不是Metal-aware Metal認識的,我們需要建立一個CAMetalLayer並告訴NSView將其用做自己的支援層.CAMetalLayerCore Animation層,它管理著一個用來渲染內容的紋理池.為了使用Metal來渲染,我們需要用這個類作為我們檢視的支援層,通過在檢視的layerClass() 類方法中返回圖層來實現:

override class func layerClass() -> AnyClass {
    return CAMetalLayer.self
}

var metalLayer: CAMetalLayer {
    return self.layer as! CAMetalLayer
}
複製程式碼

接下來,在render() 函式中建立一個新的device並告訴metalLayer去引用它,還要設定層使用的畫素格式.然後,建立一個drawable.注意,我們並沒有使用MTKView提供的currentDrawable.而是,CAMetalLayer提供了一個nextDrawable給我們使用.最後,建立一個渲染通道描述符.還是需要注意,我們沒有提供currentRenderPassDescriptor:

let device = MTLCreateSystemDefaultDevice()!
metalLayer.device = device
metalLayer.pixelFormat = .BGRA8Unorm
let drawable = metalLayer.nextDrawable()
let texture = drawable!.texture
let rpd = MTLRenderPassDescriptor()
複製程式碼

在結束本章節之前,讓我們看一下MTKView類,去看看為什麼這是在我們的app中用Metal渲染內容的最佳方式:

@available(OSX 10.11, *)
public class MTKView : NSView, NSCoding {
    public init(frame frameRect: CGRect, device: MTLDevice?)
    public init(coder: NSCoder)
    weak public var delegate: MTKViewDelegate?
    public var device: MTLDevice?
    public var currentDrawable: CAMetalDrawable? { get }
    public var framebufferOnly: Bool
    public var presentsWithTransaction: Bool
    public var colorPixelFormat: MTLPixelFormat
    public var depthStencilPixelFormat: MTLPixelFormat
    public var sampleCount: Int
    public var clearColor: MTLClearColor
    public var clearDepth: Double
    public var clearStencil: UInt32
    public var depthStencilTexture: MTLTexture? { get }
    public var multisampleColorTexture: MTLTexture? { get }
    public func releaseDrawables()
    public var currentRenderPassDescriptor: MTLRenderPassDescriptor? { get }
    public var preferredFramesPerSecond: Int
    public var enableSetNeedsDisplay: Bool
    public var autoResizeDrawable: Bool
    public var drawableSize: CGSize
    public var paused: Bool
    public func draw()
}

@available(OSX 10.11, *)
public protocol MTKViewDelegate : NSObjectProtocol {
    public func mtkView(view: MTKView, drawableSizeWillChange size: CGSize)
    public func drawInMTKView(view: MTKView)
}
複製程式碼

在這一大堆屬性中,注意我們感興趣的幾個:device, currentDrawablecurrentRenderPassDescriptor. 另一個值得注意的地方,是這個類提供了一個協議,MTKViewDelegate屬性.想要了解更多關於這些屬性和函式的知識,要去看MTKView的參考文件.

原始碼source code 已釋出在Github上.

下次見!

相關文章