我正在使用CADisplayLink实时过滤图像并将其显示在MTKView. 在我尝试使用模糊滤镜之前,所有滤镜都可以正常工作 - 在该滤镜期间,MTKView有时会开始频闪、故障或仅在某些帧上显示黑屏,而不是实际结果图像。
我有三个有趣的观察:
1)当我在中显示结果图像时没有这样的问题UIImageView,所以过滤器本身不是问题的原因
2)如果我将过滤器从模糊切换回任何其他过滤器,同样的问题也开始出现在这些过滤器中,但仅当我首先使用模糊过滤器时
3)我使用应用程序的次数越多,故障本身就会慢慢消失。我实际启动应用程序的次数越多,它甚至开始发生的次数越来越少。
代码MTKView:
import GLKit
import UIKit
import MetalKit
import QuartzCore
class MetalImageView: MTKView
{
let colorSpace = CGColorSpaceCreateDeviceRGB()
lazy var commandQueue: MTLCommandQueue =
{
[unowned self] in
return self.device!.makeCommandQueue()!
}()
lazy var ciContext: CIContext =
{
[unowned self] in
return CIContext(mtlDevice: self.device!)
}()
override init(frame frameRect: CGRect, device: MTLDevice?)
{
super.init(frame: frameRect,
device: device ?? MTLCreateSystemDefaultDevice())
if super.device == nil
{
fatalError("Device doesn't support Metal")
}
framebufferOnly = false
}
required init(coder: NSCoder)
{
fatalError("init(coder:) has not been implemented")
}
// from tutorial
private func setup() {
framebufferOnly = false
isPaused = false
enableSetNeedsDisplay = false
}
/// The image to display
var image: CIImage?
{
didSet
{
}
}
override func draw()
{
guard let
image = image,
let targetTexture = currentDrawable?.texture else
{
return
}
let commandBuffer = commandQueue.makeCommandBuffer()
let bounds = CGRect(origin: CGPoint.zero, size: drawableSize)
let originX = image.extent.origin.x
let originY = image.extent.origin.y
let scaleX = drawableSize.width / image.extent.width
let scaleY = drawableSize.height / image.extent.height
let scale = min(scaleX, scaleY)
let scaledImage = image
.transformed(by: CGAffineTransform(translationX: -originX, y: -originY))
.transformed(by: CGAffineTransform(scaleX: scale, y: scale))
ciContext.render(scaledImage,
to: targetTexture,
commandBuffer: commandBuffer,
bounds: bounds,
colorSpace: colorSpace)
commandBuffer!.present(currentDrawable!)
commandBuffer!.commit()
super.draw()
}
}
extension CGRect
{
func aspectFitInRect(target: CGRect) -> CGRect
{
let scale: CGFloat =
{
let scale = target.width / self.width
return self.height * scale <= target.height ?
scale :
target.height / self.height
}()
let width = self.width * scale
let height = self.height * scale
let x = target.midX - width / 2
let y = target.midY - height / 2
return CGRect(x: x,
y: y,
width: width,
height: height)
}
}
模糊滤镜的代码在Metal:
float4 zoneBlur(sampler src, float time, float4 touch) {
float focusPower = 2.0;
int focusDetail = 10;
float2 uv = src.coord();
float2 fingerPos;
float2 size = src.size();
if (touch.x == 0 || touch.y == 0) {
fingerPos = float2(0.5, 0.5);
} else {
fingerPos = touch.xy / size.xy;
}
float2 focus = uv - fingerPos;
float4 outColor;
outColor = float4(0, 0, 0, 1);
for (int i=0; i < focusDetail; i++) {
float power = 1.0 - focusPower * (1.0/size.x) * float(i);
outColor.rgb += src.sample(focus * power + fingerPos).rgb;
}
outColor.rgb *= 1.0 / float(focusDetail);
return outColor;
}
我想知道什么会导致这种奇怪的行为?