首页 > 解决方案 > 使用 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;
    }

我想知道什么会导致这种奇怪的行为?

标签: iosswiftmetalcore-imagecadisplaylink

解决方案


推荐阅读