ios - 使用 Metal 编写的自定义模糊过滤器时 MTKView 出现故障/频闪
问题描述
我正在使用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;
}
我想知道什么会导致这种奇怪的行为?
解决方案
推荐阅读
- javascript - .join() 在一个示例中有效,但在另一个示例中无效
- migration - 如何将现有的 20.04 ext4 安装迁移到不同磁盘上的 zfs root?
- javascript - VueJS 如何使用 x-templates 创建功能组件?
- php - 用于比较和合并值的 PHP Array 函数
- angular - 如何在 Angular 中使用“magnific-popup”
- jquery - SELECT2 AJAX - 成功调用后的操作
- python - 将类的实例传递给类
- haskell - 如何强制在 Haskell 中执行断言列表?
- java - 如何在 bean-methods 中注入字段?
- python - 在python中查找两点之间的距离,通过两个不同的对象传递输入