Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ open class BaseFilterRender {
fatalError("draw method must be overriden")
}
open func setMetalInfo(commandQueue: any MTLCommandQueue, context: CIContext) { }
open func initMetal(width: Int, height: Int, device: MTLDevice) { }
open func initMetal(device: MTLDevice) { }
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,21 @@ open class BaseShaderFilterRender: BaseFilterRender {

private var context: CIContext? = nil
private var commandQueue: MTLCommandQueue? = nil
private var device: MTLDevice? = nil
private let colorSpace: CGColorSpace = CGColorSpaceCreateDeviceRGB()
private var pipelineState: MTLRenderPipelineState? = nil
private var inputTexture: MTLTexture? = nil
private var outputTexturePreview: MTLTexture? = nil
private var outputTextureOutput: MTLTexture? = nil
public private(set) var resolution = SIMD2<Float>(640, 480)

public override func setMetalInfo(commandQueue: any MTLCommandQueue, context: CIContext) {
self.commandQueue = commandQueue
self.context = context
}

public override func initMetal(width: Int, height: Int, device: MTLDevice) {
public override func initMetal(device: MTLDevice) {
self.device = device
do {
let library = try device.makeLibrary(source: initMetalFilter(), options: nil)
guard let vertexFunction = library.makeFunction(name: "vertexFilter"),
Expand All @@ -37,22 +40,29 @@ open class BaseShaderFilterRender: BaseFilterRender {
descriptor.fragmentFunction = fragmentFunction
descriptor.colorAttachments[0].pixelFormat = .bgra8Unorm
self.pipelineState = try device.makeRenderPipelineState(descriptor: descriptor)
self.inputTexture = MetalUtils.getTexture(device: device, texture: &inputTexture, width: width, height: height)
self.outputTexturePreview = MetalUtils.getTexture(device: device, texture: &outputTexturePreview, width: width, height: height)
self.outputTextureOutput = MetalUtils.getTexture(device: device, texture: &outputTextureOutput, width: width, height: height)
} catch {
fatalError("Shader compilation failed: \(error)")
}
}

public override func draw(image: CIImage, orientation: CGImagePropertyOrientation, isPreview: Bool) -> CIImage {
let outputTexture = if isPreview { outputTexturePreview } else { outputTextureOutput }
let width = Int(image.extent.width)
let height = Int(image.extent.height)
if width <= 0 || height <= 0 { return image }
guard let pipelineState = pipelineState,
let device = device,
let commandBuffer = commandQueue?.makeCommandBuffer(),
let context = context,
let input = inputTexture,
let output = outputTexture else { return image }

let context = context else { return image }
resolution = SIMD2<Float>(Float(width), Float(height))
let output: MTLTexture?
if isPreview {
output = MetalUtils.getTexture(device: device, texture: &outputTexturePreview, width: width, height: height)
} else {
output = MetalUtils.getTexture(device: device, texture: &outputTextureOutput, width: width, height: height)
}
guard let input = MetalUtils.getTexture(device: device, texture: &inputTexture, width: width, height: height),
let output = output else { return image }

context.render(image, to: input, commandBuffer: commandBuffer, bounds: image.extent, colorSpace: colorSpace)

let descriptor = MTLRenderPassDescriptor()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public class MainRender {

private func setFilter(position: Int, baseFilterRender: BaseFilterRender) {
baseFilterRender.setMetalInfo(commandQueue: commandQueue, context: context)
baseFilterRender.initMetal(width: width, height: height, device: device)
baseFilterRender.initMetal(device: device)
if filterRenders.isEmpty && position == 0 {
addFilter(baseFilterRender: baseFilterRender)
} else {
Expand All @@ -45,13 +45,13 @@ public class MainRender {

private func addFilter(baseFilterRender: BaseFilterRender) {
baseFilterRender.setMetalInfo(commandQueue: commandQueue, context: context)
baseFilterRender.initMetal(width: width, height: height, device: device)
baseFilterRender.initMetal(device: device)
filterRenders.append(baseFilterRender)
}

private func addFilter(position: Int, baseFilterRender: BaseFilterRender) {
baseFilterRender.setMetalInfo(commandQueue: commandQueue, context: context)
baseFilterRender.initMetal(width: width, height: height, device: device)
baseFilterRender.initMetal(device: device)
filterRenders.insert(baseFilterRender, at: position)
}

Expand Down Expand Up @@ -98,8 +98,22 @@ public class MainRender {
let validFilters = filterRenders.filter {
if isPreview { $0.renderMode != .OUTPUT } else { $0.renderMode != .PREVIEW }
}
if validFilters.isEmpty { return }
var filteredImage = image.oriented(orientation)
validFilters.forEach { filter in
image = filter.draw(image: image, orientation: orientation, isPreview: isPreview)
filteredImage = filter.draw(image: filteredImage, orientation: orientation, isPreview: isPreview)
}
image = filteredImage.oriented(inverseOrientation(orientation))
}

private func inverseOrientation(_ orientation: CGImagePropertyOrientation) -> CGImagePropertyOrientation {
switch orientation {
case .left:
return .right
case .right:
return .left
default:
return orientation
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// AnalogTVFilterRender.swift
// RootEncoder
//
// Ported from Android AnalogTVFilterRender
//

import Foundation
import Metal

public class AnalogTVFilterRender: BaseShaderFilterRender {

private let startTime = Date()

public override func initMetalFilter() -> String {
return MetalUtils.readShader(name: "FilterVertex") + MetalUtils.readShader(name: "AnalogTvFilter")
}

public override func drawFilter(encoder: MTLRenderCommandEncoder) {
var time = Float(-startTime.timeIntervalSinceNow)
var res = resolution
encoder.setFragmentBytes(&time, length: MemoryLayout<Float>.size, index: 0)
encoder.setFragmentBytes(&res, length: MemoryLayout<SIMD2<Float>>.size, index: 1)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// BasicDeformationFilterRender.swift
// RootEncoder
//
// Ported from Android BasicDeformationFilterRender
//

import Foundation
import Metal

public class BasicDeformationFilterRender: BaseShaderFilterRender {

private let startTime = Date()

public override func initMetalFilter() -> String {
return MetalUtils.readShader(name: "FilterVertex") + MetalUtils.readShader(name: "BasicDeformationFilter")
}

public override func drawFilter(encoder: MTLRenderCommandEncoder) {
var time = Float(-startTime.timeIntervalSinceNow)
encoder.setFragmentBytes(&time, length: MemoryLayout<Float>.size, index: 0)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// BeautyFilterRender.swift
// RootEncoder
//
// Ported from Android BeautyFilterRender
//

import Foundation
import Metal

public class BeautyFilterRender: BaseShaderFilterRender {

public override func initMetalFilter() -> String {
return MetalUtils.readShader(name: "FilterVertex") + MetalUtils.readShader(name: "BeautyFilter")
}

public override func drawFilter(encoder: MTLRenderCommandEncoder) {
var res = SIMD2<Float>(2 / resolution.x, 2 / resolution.y)
encoder.setFragmentBytes(&res, length: MemoryLayout<SIMD2<Float>>.size, index: 0)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// BlackFilterRender.swift
// RootEncoder
//
// Ported from Android BlackFilterRender
//

import Foundation
import Metal

public class BlackFilterRender: BaseShaderFilterRender {

public override func initMetalFilter() -> String {
return MetalUtils.readShader(name: "FilterVertex") + MetalUtils.readShader(name: "BlackFilter")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// BlurFilterRender.swift
// RootEncoder
//
// Ported from Android BlurFilterRender
//

import Foundation
import Metal

public class BlurFilterRender: BaseShaderFilterRender {

public var blur: Float = 10
public var radius: Float = 0.03

public override func initMetalFilter() -> String {
return MetalUtils.readShader(name: "FilterVertex") + MetalUtils.readShader(name: "BlurFilter")
}

public override func drawFilter(encoder: MTLRenderCommandEncoder) {
encoder.setFragmentBytes(&blur, length: MemoryLayout<Float>.size, index: 0)
encoder.setFragmentBytes(&radius, length: MemoryLayout<Float>.size, index: 1)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// BrightnessFilterRender.swift
// RootEncoder
//
// Ported from Android BrightnessFilterRender
//

import Foundation
import Metal

public class BrightnessFilterRender: BaseShaderFilterRender {

public var brightness: Float = 0.5

public override func initMetalFilter() -> String {
return MetalUtils.readShader(name: "FilterVertex") + MetalUtils.readShader(name: "BrightnessFilter")
}

public override func drawFilter(encoder: MTLRenderCommandEncoder) {
encoder.setFragmentBytes(&brightness, length: MemoryLayout<Float>.size, index: 0)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// CartoonFilterRender.swift
// RootEncoder
//
// Ported from Android CartoonFilterRender
//

import Foundation
import Metal

public class CartoonFilterRender: BaseShaderFilterRender {

public var cartoon: Float = 0.007

public override func initMetalFilter() -> String {
return MetalUtils.readShader(name: "FilterVertex") + MetalUtils.readShader(name: "CartoonFilter")
}

public override func drawFilter(encoder: MTLRenderCommandEncoder) {
encoder.setFragmentBytes(&cartoon, length: MemoryLayout<Float>.size, index: 0)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// ChromaticAberrationFilterRender.swift
// RootEncoder
//
// Ported from Android ChromaticAberrationFilterRender
//

import Foundation
import Metal

public class ChromaticAberrationFilterRender: BaseShaderFilterRender {

private let startTime = Date()

public override func initMetalFilter() -> String {
return MetalUtils.readShader(name: "FilterVertex") + MetalUtils.readShader(name: "ChromaticAberrationFilter")
}

public override func drawFilter(encoder: MTLRenderCommandEncoder) {
var time = Float(-startTime.timeIntervalSinceNow)
encoder.setFragmentBytes(&time, length: MemoryLayout<Float>.size, index: 0)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//
// CircleFilterRender.swift
// RootEncoder
//
// Ported from Android CircleFilterRender
//

import Foundation
import Metal

public class CircleFilterRender: BaseShaderFilterRender {

public var radius: Float = 0.5
//center of the circle in percent (0.0 to 1.0)
public var center = SIMD2<Float>(0.5, 0.5)

public override func initMetalFilter() -> String {
return MetalUtils.readShader(name: "FilterVertex") + MetalUtils.readShader(name: "CircleFilter")
}

public override func drawFilter(encoder: MTLRenderCommandEncoder) {
var res = resolution
encoder.setFragmentBytes(&radius, length: MemoryLayout<Float>.size, index: 0)
encoder.setFragmentBytes(&center, length: MemoryLayout<SIMD2<Float>>.size, index: 1)
encoder.setFragmentBytes(&res, length: MemoryLayout<SIMD2<Float>>.size, index: 2)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//
// ColorFilterRender.swift
// RootEncoder
//
// Ported from Android ColorFilterRender
//

import Foundation
import Metal

public class ColorFilterRender: BaseShaderFilterRender {

//color in percent (0.0 to 1.0)
public var color = SIMD3<Float>(0, 0, 1)

public override func initMetalFilter() -> String {
return MetalUtils.readShader(name: "FilterVertex") + MetalUtils.readShader(name: "ColorFilter")
}

public func setRGBColor(r: Int, g: Int, b: Int) {
color = SIMD3<Float>(Float(r) / 255, Float(g) / 255, Float(b) / 255)
}

public override func drawFilter(encoder: MTLRenderCommandEncoder) {
encoder.setFragmentBytes(&color, length: MemoryLayout<SIMD3<Float>>.size, index: 0)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// ContrastFilterRender.swift
// RootEncoder
//
// Ported from Android ContrastFilterRender
//

import Foundation
import Metal

public class ContrastFilterRender: BaseShaderFilterRender {

public var contrast: Float = 0.5

public override func initMetalFilter() -> String {
return MetalUtils.readShader(name: "FilterVertex") + MetalUtils.readShader(name: "ContrastFilter")
}

public override func drawFilter(encoder: MTLRenderCommandEncoder) {
encoder.setFragmentBytes(&contrast, length: MemoryLayout<Float>.size, index: 0)
}
}
Loading