CAMetalLayer nextDrawable, возвращающий ноль, потому что распределение не удалось - PullRequest
0 голосов
/ 18 марта 2020

Я новичок в разработке Swift и Ma c и пытаюсь создать фреймворк (только macOS), который может открывать металлическое окно. Я использую Xcode версии 11.3.1 на macOS версии 10.15.2.

Я начал с примеров, которые нашел в Интернете (запуск проекта macOS / Command Line Tool), и я не вижу, как это исправить ошибка:

[CAMetalLayer nextDrawable], возвращающий ноль, потому что распределение не удалось.

Когда проект создается с раскадровкой (проект MacOS / App), открывается окно с ожидаемым содержимое (заполнение красным цветом), но когда я пытаюсь заменить раскадровку на код (проект macOS / Command Line Tool), выполнение повторяется из-за указанной выше ошибки.

Main.swift

import AppKit

class AppDelegate: NSObject, NSApplicationDelegate {
    var window: NSWindow!
    var viewController: ViewController!

    func applicationDidFinishLaunching(_ notification: Notification) {
        NSLog("Start app")

        viewController = ViewController()
        window = NSWindow(contentRect: NSMakeRect(0, 0, 1024, 768),
                          styleMask: .borderless,
                          backing: .buffered,
                          defer: false)

        window.contentViewController = viewController
        window.title = "Hey, new Window!"
        window.backgroundColor = NSColor.blue
        window.orderFrontRegardless()
    }

    func applicationWillTerminate(_ notification: Notification) {
        NSLog("Terminate app")
    }

    func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
        return true
    }
}

let app = NSApplication.shared
let appDelegate = AppDelegate()
app.delegate = appDelegate

app.run()

ViewController.swift

import Cocoa
import Metal
import MetalKit

class ViewController: NSViewController {

    var mtkView: MTKView!
    var renderer: Renderer!

    override func loadView() {
        mtkView = MTKView()
        self.view = mtkView
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        guard let defaultDevice = MTLCreateSystemDefaultDevice() else {
            print("Metal is not supported on this device")
            return
        }

        print("My GPU is: \(defaultDevice)")
        mtkView.device = defaultDevice

        guard let tempRenderer = Renderer(mtkView: mtkView) else {
            print("Renderer failed to initialize")
            return
        }
        renderer = tempRenderer

        mtkView.delegate = renderer
    }

    override var representedObject: Any? {
        didSet {
        // Update the view, if already loaded.
        }
    }
}

Renderer.swift

import Foundation
import Metal
import MetalKit

class Renderer : NSObject, MTKViewDelegate {

    let device: MTLDevice
    let commandQueue: MTLCommandQueue

    init?(mtkView: MTKView) {
        device = mtkView.device!
        commandQueue = device.makeCommandQueue()!
    }

    func draw(in view: MTKView) {
        guard let commandBuffer = commandQueue.makeCommandBuffer() else { return }

        guard let renderPassDescriptor = view.currentRenderPassDescriptor else { return }

        renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(1, 0, 0, 1)

        guard let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor) else { return }

        renderEncoder.endEncoding()

        commandBuffer.present(view.currentDrawable!)

        commandBuffer.commit()
    }

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

    }
}

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

1 Ответ

2 голосов
/ 18 марта 2020

Самая насущная проблема здесь заключается в том, что ваш CAMetalLayer, слой, который поддерживает ваш MTKView, имеет размер (0, 0). Поэтому слой не может выделять рисованные элементы для рисования.

Причина, по которой ваш слой имеет нулевой размер, заключается в том, что ваш MTKView имеет нулевой размер, а причина, по которой ваш вид имеет нулевой размер, в том, что вы его создаете без указания кадра. Согласно документации, «Установка contentViewController приводит к изменению размера окна на основе текущего размера contentViewController;» следовательно, ваше окно также имеет нулевой размер.

Укажите размер при создании MTKView, и все будет "работать":

mtkView = MTKView(frame: NSMakeRect(0, 0, 100, 100))

Повторяя комментарии выше, я рекомендую против такого подхода, поскольку Метод NSApplication run() не делает все необходимое, чтобы сделать приложение хорошим гражданином macOS. В приложении не будет плитки Dock, не будет главного меню, и вы не сможете использовать обычные сочетания клавиш, такие как Cmd + Q, без дополнительных усилий. Если вы разрабатываете фреймворк, чтобы людям было проще создавать windows с минимальными усилиями, это слишком мало. Также невозможно и не поддерживается реализация всего, что NSApplicationMain делает от вашего имени, с помощью API publi c. Поощряйте пользователей вашей платформы следовать шаблонам проектирования платформы, а не пытаться отобрать у них контроль во имя простоты. Если они уже запускают полноценное приложение с правильным запуском l oop, вы можете создать windows от их имени, не касаясь слоя NSApplication.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...