LoginSignup
14
14

More than 5 years have passed since last update.

MTKViewとCAMetalLayerの実装差分

Last updated at Posted at 2018-05-05

海外のMetalの解説書を読むと、大抵の場合、画面への描画にはまずCAMetalLayerを使う。MTKViewではなく。

この理由はわかる。MTKViewはラッパークラスであって、内部的にはCAMetalLayerを使っている。ので、まずはCAMetalLayerから学んでいこう、と。

An MTKView object is backed by a CAMetalLayer object

それは正しいと思うが、個人的にはGPUプログラミング初心者はMTKViewから始めたほうがいいと思っている。新しい概念がたくさん登場するので、ラッパーで簡単化できる部分があるのならその恩恵にあずかったほうが挫折の可能性が下がるかなと。

で、MTKViewは、CAMetalLayerを直に使うことに比べて、具体的に何をどのように簡単化してくれているのだろうか。そのへんを整理するため、実装差分をこの記事で書き出してみる。

初期化

  • MTKViewの場合
let mtkView = MTKView(frame: frame)
  • CAMetalLayerの場合
metalLayer = CAMetalLayer()
metalLayer.frame = frame

内部ではいろいろとあるかもしれないが、API的にはframeをイニシャライザでセットできるかどうかの違いしかない。

セットアップ

  • MTKViewの場合
mtkView.device = device
view.addSubview(mtkView)

mtkView.delegate = self
  • CAMetalLayerの場合
metalLayer.device = device
view.layer.addSublayer(metalLayer)

let link = CADisplayLink(target: self, selector: #selector(onDisplayLink))
link.add(to: .current, forMode: .defaultRunLoopMode)

MTKViewはdelegateでループを処理するが、CAMetalLayerの場合は自分でループのしくみを用意する。

ピクセルフォーマットを合わせる

これは同じ

metalLayer.pixelFormat = texture.pixelFormat
mtkView.colorPixelFormat = texture.pixelFormat

レンダリングループの実装

  • MTKViewの場合
func draw(in: view) {
    autoreleasepool {
        render()
    }
}
  • CAMetalLayerの場合
@objc func onDisplayLink() {
    autoreleasepool {
        render()
    }
}

まとめ

あれ・・・結果としては、そんなに変わらない感じだった。レンダリングループを自前実装するか、delegateを使うか、という差はあるが、そんなに労力が減っている感はない。

簡単になるのは上で省略した、レンダリング時の、ドローアブルとかrender pass descriptorのハンドリングなのかもしれない。

Using an MTKView object is the preferred way to interact with drawables. An MTKView object is backed by a CAMetalLayer object and provides the currentDrawable property to acquire the drawable for the current frame. The current frame renders into this drawable and the presentDrawable: method schedules the actual presentation to occur at the next display refresh interval. The currentDrawable property is automatically updated at the end of every frame.

An MTKView object also provides the currentRenderPassDescriptor convenience property that references the current drawable’s texture; use this property to create a render command encoder that renders into the current drawable. A call to the currentRenderPassDescriptor property implicitly acquires the drawable for the current frame, which is then stored in the currentDrawable property.

If you create your own UIView or NSView subclass that is backed by a CAMetalLayer object, you must explicitly acquire a drawable and use its texture to configure a render pass descriptor. You can also do this for your own MTKView object, but it is much easier to simply use the currentRenderPassDescriptor convenience property. For an example of how to acquire a drawable from a UIView or NSView subclass, see the MetalBasic3D sample.

https://developer.apple.com/library/content/documentation/3DDrawing/Conceptual/MTLBestPracticesGuide/Drawables.html)

14
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
14