【发布时间】:2016-01-29 06:52:39
【问题描述】:
我觉得我必须在这里遗漏一些东西。我已经对NSOpenGLView 进行了子类化,并且我试图在drawRect: 调用中绘制CIImage。
override func drawRect(dirtyRect: NSRect) {
super.drawRect(dirtyRect)
let start = CFAbsoluteTimeGetCurrent()
openGLContext!.makeCurrentContext()
let cglContext = openGLContext!.CGLContextObj
let pixelFormat = openGLContext!.pixelFormat.CGLPixelFormatObj
let colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB)!
let options: [String: AnyObject] = [kCIContextOutputColorSpace: colorSpace]
let context = CIContext(CGLContext: cglContext, pixelFormat: pixelFormat, colorSpace: colorSpace, options: options)
context.drawImage(inputImage, inRect: self.bounds, fromRect: input.extent)
openGLContext!.flushBuffer()
let end = CFAbsoluteTimeGetCurrent()
Swift.print("updated view in \(end - start)")
}
我显然错误地认为NSOpenGLContext(及其底层CGLContext)可以包装在CIContext 中,并且渲染到该CIContext 中会在视图中生成图像。但是,虽然在上面的代码中完成了工作,但我不知道实际像素在哪里结束(因为视图最终是空白的)。
如果我只是抓取当前的NSGraphicsContext 并渲染到其中,那么我会在NSOpenGLView 中得到一个图像,但渲染似乎需要大约 10 倍的时间(即通过将 CIContext 声明更改为此) :
// Works, but is slow
let context = NSGraphicsContext.currentContext()!.CIContext!
也试过这个,既慢又不实际显示图像,使其双重失败:
// Doesn't work. AND it's slow.
input.drawInRect(bounds, fromRect: input.extent, operation: .CompositeDestinationAtop, fraction: 1.0)
简单的解决方案是渲染到CGImage,然后将其弹出到屏幕上(通过CGImage -> NSImage,然后是NSImageView,或支持CALayer)。但这对我的情况来说还不够高效。在我的应用程序中,我希望渲染几十个缩略图大小的图像,每个图像都有自己不同的CIFilters 链,并随着基础图像的变化实时刷新它们。虽然它们每个都在几毫秒内渲染(使用我当前的 CGImage-bracketed 路径),但视图更新仍然是每秒几帧的数量级。
我目前正在使用类似于CGImageRef -> CIImage -> Bunch of CIFilters -> CGImage -> assign to CALayer for display 的路径。但似乎在渲染链的两端都有CGImages 会影响性能。
分析后,似乎大部分时间都花在了复制内存上,我认为这是预期的,但效率不高。支持的 CGImage 需要穿梭到 GPU,然后过滤,然后以 CGImage 的形式返回主内存,然后(可能)直接返回 GPU 以由CALayer。理想情况下,根图像(过滤之前)将只位于 GPU 上,结果将直接呈现到视频内存,但我不知道如何实现这一点。我当前的渲染路径在 GPU 上完成了像素粉碎(这太棒了!),但是被到处穿梭的内存淹没以实际显示该死的东西。
那么,任何人都可以告诉我如何使用将事物端到端保持在 GPU 上的路径进行核心图像过滤吗? (或者至少只需要交换一次数据?)如果我有一个支持 IOSurface 的 CIImage,我如何在不影响主内存的情况下直接将其绘制到 UI 上?有什么提示吗?
【问题讨论】:
标签: objective-c swift cocoa gpu core-image