1

I created test application with ViewController, GLKView and UISlider. Slider change value in selected filter. Rendering image very slow. What's wrong with my code?

Test class of GLKview:

import UIKit
import CoreImage
import GLKit

class CustomGLView: GLKView {
    //test filters 
    let clampFilter = CIFilter(name: "CIAffineClamp")!
    let blurFilter = CIFilter(name: "CIGaussianBlur")!
    let ciContext:CIContext

    override init(frame: CGRect) {
        let glContext = EAGLContext(api: .openGLES2)
        ciContext = CIContext(
            eaglContext: glContext!,
            options: [
                kCIContextWorkingColorSpace: NSNull()
            ]
        )
        super.init(frame: frame, context: glContext!)
        enableSetNeedsDisplay = true
    }

    required init(coder aDecoder: NSCoder) {
        let glContext = EAGLContext(api: .openGLES2)
        ciContext = CIContext(
            eaglContext: glContext!,
            options: [
                kCIContextWorkingColorSpace: NSNull()
            ]
        )
        super.init(coder: aDecoder)!
        context = glContext!
        enableSetNeedsDisplay = true
    }

      var inputImage: UIImage? {
        didSet {
            inputCIImage = inputImage.map { CIImage(image: $0)! }
        }
    }

     var blurRadius: Float = 0 {
        didSet {
            blurFilter.setValue(blurRadius, forKey: "inputRadius")
            setNeedsDisplay()
        }
    }

    var inputCIImage: CIImage? {
        didSet { setNeedsDisplay() }
    }

    override func draw(_ rect: CGRect) {
        if let inputCIImage = inputCIImage {
            clampFilter.setValue(inputCIImage, forKey: kCIInputImageKey)
            blurFilter.setValue(clampFilter.outputImage!, forKey: kCIInputImageKey)
            let rect = CGRect(x: 0, y: 0, width: drawableWidth, height: drawableHeight)
            ciContext.draw(blurFilter.outputImage!, in: rect, from: inputCIImage.extent)
        }
    } 
}

How I change value in CIFilter:

import UIKit
import GLKit
import CoreImage

    class ViewController: UIViewController {
        //image
         let imageOriginal = UIImage(named: "pic_2")
         //my GLKView
        @IBOutlet weak var glView: CustomGLView!

        override func viewDidLoad() {
                super.viewDidLoad()
                //test image
                self.glView.inputImage = self.imageOriginal

            }

        @IBAction func mySlider(_ sender: UISlider) {

                self.glView.blurRadius = sender.value
            }
    }
BDL
  • 21,052
  • 22
  • 49
  • 55
Metman
  • 336
  • 3
  • 14

1 Answers1

6

Creating a CIImage from UIImage may require extra time to copy the image data from memory to GPU memory. Try loading your image into a GPU texture and then creating a CIImage backed by this texture using CIImage(texture:size:flipped:colorSpace:)

Make sure you're only creating the texture once, not at the start of every draw(_:).

You could also try:

  • Making sure the blur radius isn't too large. A gaussian blur is an expensive operation and it will take longer the greater the blur radius.
  • Using a smaller image. If you need larger images, you may want to scale the image down first, apply the blur, and then scale back up (see here for an explanation). Halving the width and height will reduce the number of pixels by a factor of 4.
  • UISlider will change at a rate of 60 per second. Reducing the frame rate to 30 fps will give you double the time to render each image.
Binary Pulsar
  • 1,209
  • 10
  • 17