swift - CAMetalLayer nextDrawable 返回 nil 因为分配失败
问题描述
我是 Swift 和 Mac 开发的新手,我正在尝试制作一个可以打开 Metal 窗口的框架(仅限 macOS)。我在 macOS 版本 10.15.2 上使用 Xcode 版本 11.3.1。
我从我在网上找到的示例开始(macOS/命令行工具项目开始),我看不到如何纠正这个错误:
[CAMetalLayer nextDrawable] 因为分配失败而返回 nil。
当使用情节提要(macOS/App 项目)创建项目时,窗口会打开并显示预期的内容(填充为红色),但是当我尝试用代码(macOS/命令行工具项目)替换情节提要时,执行循环会出现错误上文提到的 。
主.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.
}
}
}
渲染器.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
但并没有解决我的问题。
解决方案
这里最直接的问题是你CAMetalLayer
的,支持你的层,MTKView
大小为 (0, 0)。因此,图层无法分配可绘制对象供您绘制。
您的图层大小为零的原因是因为您的MTKView
大小为零,而您的视图大小为零的原因是因为您在没有指定框架的情况下创建了它。根据文档,“设置contentViewController
会导致窗口根据 ; 的当前大小调整大小contentViewController
” 因此您的窗口大小也为零。
在创建你的东西时提供一个大小MTKView
,事情会“工作”:
mtkView = MTKView(frame: NSMakeRect(0, 0, 100, 100))
与上面的评论相呼应,我建议不要使用这种方法,因为NSApplication
' 的run()
方法并没有做所有必要的事情来使应用程序成为一个好的 macOS 公民。该应用程序没有 Dock 磁贴,没有主菜单,并且您将无法使用 Cmd+Q 等常用键盘快捷键而无需付出额外的努力。如果您正在设计一个框架以使人们更轻松地以最少的努力创建窗口,那么这太少了。也不可能也不支持NSApplicationMain
使用公共 API 实现代表您所做的一切。鼓励您的框架的用户遵循平台设计模式,而不是试图以简单的名义从他们手中夺取控制权。如果他们已经在运行具有适当运行循环的成熟应用程序,NSApplication
地层。
推荐阅读
- javascript - 如何使网格行大小保持不变,并使文本自行调整大小?
- flutter-layout - 使一些透视 3d 平面在颤动中相互交叉
- python - 将字符串逐列格式化为矩阵
- javascript - this._xyz 中的下划线是什么意思?
- kotlin - Kotlin 中没有高阶函数的内联关键字
- plot - 无论策略如何,OfflineReplayEvaluatorBandit 都显示相同的情节 (r)
- python - 无法在带有 xvid 编解码器和轻子摄像头的 python 中使用 opencv 保存视频
- java - 如何使用 Optional.ofNullable() 简化 if 语句
- python - 在python中将字符串放在字符串旁边
- python-3.x - tkinter:将鼠标滚轮绑定到多个框架中多个画布中的滚动条