Metal API View не имеет дескриптора прохода рендеринга - PullRequest
0 голосов
/ 20 апреля 2020

В настоящее время я пытаюсь создать металлическое приложение без использования IB в XCode (чисто программно, без раскадровки), и у меня возникли некоторые проблемы с рендерингом с использованием MTKView Delegate.

Я создал следующие 3 класса

Делегат приложения:

import Cocoa
import MetalKit

class AppDelegate: NSObject, NSApplicationDelegate
{
    var newWindow: NSWindow?
    var controller: ViewController?

    func applicationDidFinishLaunching(_ notification: Notification) {
        newWindow = NSWindow(contentRect: NSMakeRect(10, 10, 300, 300), styleMask: [.miniaturizable, .closable, .resizable, .titled], backing: .buffered, defer: false)

        controller = ViewController()
        let content = newWindow!.contentView! as NSView
        let view = controller!.view
        content.addSubview(view)
        newWindow!.makeKeyAndOrderFront(nil)
    }

}

Контроллер представления:

import Cocoa
import MetalKit

class ViewController: NSViewController {

    var renderer: Renderer?

    override func loadView() {
        view = MTKView.init()
    }

    override func viewDidLoad() {
        guard let metalView = view as? MTKView else {
            fatalError("Cant Get Metal View")
        }

        super.viewDidLoad()

        renderer = Renderer(metalView: metalView)
    }
}

Renderer.swift:

import MetalKit

class Renderer: NSObject {

  static var device: MTLDevice!
  static var commandQueue: MTLCommandQueue!
  var mesh: MTKMesh!
  var vertexBuffer: MTLBuffer!
  var pipelineState: MTLRenderPipelineState!

  init(metalView: MTKView) {

    guard
      let device = MTLCreateSystemDefaultDevice(),
      let commandQueue = device.makeCommandQueue() else {
        fatalError("GPU not available")
    }

    Renderer.device = device
    Renderer.commandQueue = commandQueue
    metalView.device = device

    let mdlMesh = Primative.makeCube(device: device, size: 1)

    do {
      mesh = try MTKMesh(mesh: mdlMesh, device: device)
    } catch let error {
      print(error.localizedDescription)
    }
    vertexBuffer = mesh.vertexBuffers[0].buffer

    let library = device.makeDefaultLibrary()
    let vertexFunction = library?.makeFunction(name: "vertex_main")
    let fragmentFunction = library?.makeFunction(name: "fragment_main")

    let pipelineDescriptor = MTLRenderPipelineDescriptor()
    pipelineDescriptor.vertexFunction = vertexFunction
    pipelineDescriptor.fragmentFunction = fragmentFunction
    pipelineDescriptor.vertexDescriptor =
      MTKMetalVertexDescriptorFromModelIO(mdlMesh.vertexDescriptor)
    pipelineDescriptor.colorAttachments[0].pixelFormat = metalView.colorPixelFormat
    do {
      pipelineState = try device.makeRenderPipelineState(descriptor: pipelineDescriptor)
    } catch let error {
      fatalError(error.localizedDescription)
    }

    super.init()
    metalView.clearColor = MTLClearColor(red: 1.0, green: 1.0,
                                         blue: 0.8, alpha: 1.0)
    metalView.delegate = self
  }
}

extension Renderer: MTKViewDelegate {
  func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {

  }

  func draw(in view: MTKView) {
    // Creating Render Pass Descriptor
        if let descriptor = view.currentRenderPassDescriptor
        {
            print("Drawing")
        }
        else {
            print("Not Drawing")
        }
    }
}

Эти три класса хорошо визуализируют Окно, и вывод

Not Drawing

Показывает, что это значение всегда равно нулю, но оно что-то делает каждый кадр.

Вещи Я попытался

  • Создание собственного дескриптора прохода рендеринга: это привело к ошибке sig.
  • Проверил представление, определенно распознав MTKView

Я знаю, что это работает, если я использую проект, основанный на раскадровке в файле, но надеялся узнать, как это сделать без него.

Любая помощь будет принята с благодарностью

Ответы [ 2 ]

1 голос
/ 20 апреля 2020

Из документов MTKView.currentRenderPassDescriptor:

Это свойство равно nil, если свойство представления device не установлено или если currentDrawable равно nil.

Вам нужно дать MTKView металлическое устройство для работы. Возможно, IB по умолчанию задает MTLCreateSystemDefaultDevice(), но когда вы создаете представление программно, вам нужно сделать это вручную:

override func loadView() {
    view = MTKView(frame: .zero, device: MTLCreateSystemDefaultDevice())
}
0 голосов
/ 20 апреля 2020

Ширина и высота вида 0. Установите размер кадра перед добавлением вида в окно в applicationDidFinishLaunching.

controller = ViewController()
let content = newWindow!.contentView! as NSView
let view = controller!.view
view.frame = content.bounds
content.addSubview(view)
...