2024-05-07 20:05:50 +04:00

209 lines
12 KiB
Swift

import Foundation
import MetalKit
import LottieCpp
final class PathRenderContext {
let device: MTLDevice
let msaaSampleCount: Int
let prepareBezierPipelineState: MTLComputePipelineState
let shapePipelineState: MTLRenderPipelineState
let clearPipelineState: MTLRenderPipelineState
let mergeColorFillPipelineState: MTLRenderPipelineState
let mergeLinearGradientFillPipelineState: MTLRenderPipelineState
let mergeRadialGradientFillPipelineState: MTLRenderPipelineState
let strokeTerminalPipelineState: MTLRenderPipelineState
let strokeInnerPipelineState: MTLRenderPipelineState
let drawOffscreenPipelineState: MTLRenderPipelineState
let drawOffscreenWithMaskPipelineState: MTLRenderPipelineState
let maximumThreadGroupWidth: Int
init?(device: MTLDevice, msaaSampleCount: Int) {
self.device = device
self.msaaSampleCount = msaaSampleCount
self.maximumThreadGroupWidth = device.maxThreadsPerThreadgroup.width
guard let library = metalLibrary(device: device) else {
return nil
}
guard let quadVertexFunction = library.makeFunction(name: "quad_vertex_shader") else {
print("Unable to find vertex function. Are you sure you defined it and spelled the name right?")
return nil
}
guard let shapeVertexFunction = library.makeFunction(name: "fill_vertex_shader") else {
print("Unable to find vertex function. Are you sure you defined it and spelled the name right?")
return nil
}
guard let shapeFragmentFunction = library.makeFunction(name: "fragment_shader") else {
print("Unable to find fragment function. Are you sure you defined it and spelled the name right?")
return nil
}
guard let clearFragmentFunction = library.makeFunction(name: "clear_mask_fragment") else {
print("Unable to find fragment function. Are you sure you defined it and spelled the name right?")
return nil
}
guard let mergeColorFillFragmentFunction = library.makeFunction(name: "merge_color_fill_fragment_shader") else {
print("Unable to find fragment function. Are you sure you defined it and spelled the name right?")
return nil
}
guard let mergeLinearGradientFillFragmentFunction = library.makeFunction(name: "merge_linear_gradient_fill_fragment_shader") else {
print("Unable to find fragment function. Are you sure you defined it and spelled the name right?")
return nil
}
guard let mergeRadialGradientFillFragmentFunction = library.makeFunction(name: "merge_radial_gradient_fill_fragment_shader") else {
print("Unable to find fragment function. Are you sure you defined it and spelled the name right?")
return nil
}
guard let strokeFragmentFunction = library.makeFunction(name: "stroke_fragment_shader") else {
print("Unable to find fragment function. Are you sure you defined it and spelled the name right?")
return nil
}
guard let strokeTerminalVertexFunction = library.makeFunction(name: "strokeTerminalVertex") else {
print("Unable to find fragment function. Are you sure you defined it and spelled the name right?")
return nil
}
guard let strokeInnerVertexFunction = library.makeFunction(name: "strokeInnerVertex") else {
print("Unable to find fragment function. Are you sure you defined it and spelled the name right?")
return nil
}
guard let prepareBezierPipelineFunction = library.makeFunction(name: "evaluateBezier") else {
print("Unable to find fragment function. Are you sure you defined it and spelled the name right?")
return nil
}
guard let quadOffscreenFragmentFunction = library.makeFunction(name: "quad_offscreen_fragment") else {
print("Unable to find fragment function. Are you sure you defined it and spelled the name right?")
return nil
}
guard let quadOffscreenWithMaskFragmentFunction = library.makeFunction(name: "quad_offscreen_fragment_with_mask") else {
print("Unable to find fragment function. Are you sure you defined it and spelled the name right?")
return nil
}
self.prepareBezierPipelineState = try! device.makeComputePipelineState(function: prepareBezierPipelineFunction)
let shapePipelineDescriptor = MTLRenderPipelineDescriptor()
shapePipelineDescriptor.vertexFunction = shapeVertexFunction
shapePipelineDescriptor.fragmentFunction = shapeFragmentFunction
shapePipelineDescriptor.colorAttachments[0].pixelFormat = .bgra8Unorm
shapePipelineDescriptor.colorAttachments[0].writeMask = []
shapePipelineDescriptor.colorAttachments[1].pixelFormat = .bgra8Unorm
shapePipelineDescriptor.colorAttachments[1].writeMask = [.all]
shapePipelineDescriptor.rasterSampleCount = msaaSampleCount
guard let shapePipelineState = try? device.makeRenderPipelineState(descriptor: shapePipelineDescriptor) else {
preconditionFailure()
}
self.shapePipelineState = shapePipelineState
let clearPipelineDescriptor = MTLRenderPipelineDescriptor()
clearPipelineDescriptor.vertexFunction = quadVertexFunction
clearPipelineDescriptor.fragmentFunction = clearFragmentFunction
clearPipelineDescriptor.colorAttachments[0].pixelFormat = .bgra8Unorm
clearPipelineDescriptor.colorAttachments[0].writeMask = []
clearPipelineDescriptor.colorAttachments[1].pixelFormat = .bgra8Unorm
clearPipelineDescriptor.colorAttachments[1].writeMask = .all
clearPipelineDescriptor.rasterSampleCount = msaaSampleCount
guard let clearPipelineState = try? device.makeRenderPipelineState(descriptor: clearPipelineDescriptor) else {
preconditionFailure()
}
self.clearPipelineState = clearPipelineState
let mergePipelineDescriptor = MTLRenderPipelineDescriptor()
mergePipelineDescriptor.vertexFunction = quadVertexFunction
mergePipelineDescriptor.colorAttachments[0].pixelFormat = .bgra8Unorm
mergePipelineDescriptor.colorAttachments[0].writeMask = [.all]
mergePipelineDescriptor.colorAttachments[0].isBlendingEnabled = true
mergePipelineDescriptor.colorAttachments[0].rgbBlendOperation = .add
mergePipelineDescriptor.colorAttachments[0].alphaBlendOperation = .add
mergePipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = .one
mergePipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = .one
mergePipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = .oneMinusSourceAlpha
mergePipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = .one
mergePipelineDescriptor.rasterSampleCount = msaaSampleCount
mergePipelineDescriptor.colorAttachments[1].pixelFormat = .bgra8Unorm
mergePipelineDescriptor.colorAttachments[1].writeMask = []
mergePipelineDescriptor.fragmentFunction = mergeColorFillFragmentFunction
guard let mergeColorFillPipelineState = try? device.makeRenderPipelineState(descriptor: mergePipelineDescriptor) else {
preconditionFailure()
}
self.mergeColorFillPipelineState = mergeColorFillPipelineState
mergePipelineDescriptor.fragmentFunction = mergeLinearGradientFillFragmentFunction
guard let mergeLinearGradientFillPipelineState = try? device.makeRenderPipelineState(descriptor: mergePipelineDescriptor) else {
preconditionFailure()
}
self.mergeLinearGradientFillPipelineState = mergeLinearGradientFillPipelineState
mergePipelineDescriptor.fragmentFunction = mergeRadialGradientFillFragmentFunction
guard let mergeRadialGradientFillPipelineState = try? device.makeRenderPipelineState(descriptor: mergePipelineDescriptor) else {
preconditionFailure()
}
self.mergeRadialGradientFillPipelineState = mergeRadialGradientFillPipelineState
let strokePipelineDescriptor = MTLRenderPipelineDescriptor()
strokePipelineDescriptor.fragmentFunction = strokeFragmentFunction
strokePipelineDescriptor.colorAttachments[0].pixelFormat = .bgra8Unorm
strokePipelineDescriptor.colorAttachments[0].writeMask = [.all]
strokePipelineDescriptor.colorAttachments[0].isBlendingEnabled = true
strokePipelineDescriptor.colorAttachments[0].rgbBlendOperation = mergePipelineDescriptor.colorAttachments[0].rgbBlendOperation
strokePipelineDescriptor.colorAttachments[0].alphaBlendOperation = mergePipelineDescriptor.colorAttachments[0].alphaBlendOperation
strokePipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = mergePipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor
strokePipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = mergePipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor
strokePipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = mergePipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor
strokePipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = mergePipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor
strokePipelineDescriptor.rasterSampleCount = msaaSampleCount
strokePipelineDescriptor.colorAttachments[1].pixelFormat = .bgra8Unorm
strokePipelineDescriptor.colorAttachments[1].writeMask = []
strokePipelineDescriptor.vertexFunction = strokeTerminalVertexFunction
guard let strokeTerminalPipelineState = try? device.makeRenderPipelineState(descriptor: strokePipelineDescriptor) else {
preconditionFailure()
}
self.strokeTerminalPipelineState = strokeTerminalPipelineState
strokePipelineDescriptor.vertexFunction = strokeInnerVertexFunction
guard let strokeInnerPipelineState = try? device.makeRenderPipelineState(descriptor: strokePipelineDescriptor) else {
preconditionFailure()
}
self.strokeInnerPipelineState = strokeInnerPipelineState
let drawOffscreenPipelineDescriptor = MTLRenderPipelineDescriptor()
drawOffscreenPipelineDescriptor.vertexFunction = quadVertexFunction
drawOffscreenPipelineDescriptor.colorAttachments[0].pixelFormat = .bgra8Unorm
drawOffscreenPipelineDescriptor.colorAttachments[0].writeMask = [.all]
drawOffscreenPipelineDescriptor.colorAttachments[1].pixelFormat = .bgra8Unorm
drawOffscreenPipelineDescriptor.colorAttachments[1].writeMask = []
drawOffscreenPipelineDescriptor.rasterSampleCount = msaaSampleCount
drawOffscreenPipelineDescriptor.colorAttachments[0].isBlendingEnabled = true
drawOffscreenPipelineDescriptor.colorAttachments[0].rgbBlendOperation = mergePipelineDescriptor.colorAttachments[0].rgbBlendOperation
drawOffscreenPipelineDescriptor.colorAttachments[0].alphaBlendOperation = mergePipelineDescriptor.colorAttachments[0].alphaBlendOperation
drawOffscreenPipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor = mergePipelineDescriptor.colorAttachments[0].sourceRGBBlendFactor
drawOffscreenPipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor = mergePipelineDescriptor.colorAttachments[0].sourceAlphaBlendFactor
drawOffscreenPipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor = mergePipelineDescriptor.colorAttachments[0].destinationRGBBlendFactor
drawOffscreenPipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor = mergePipelineDescriptor.colorAttachments[0].destinationAlphaBlendFactor
drawOffscreenPipelineDescriptor.fragmentFunction = quadOffscreenFragmentFunction
guard let drawOffscreenPipelineState = try? device.makeRenderPipelineState(descriptor: drawOffscreenPipelineDescriptor) else {
preconditionFailure()
}
self.drawOffscreenPipelineState = drawOffscreenPipelineState
drawOffscreenPipelineDescriptor.fragmentFunction = quadOffscreenWithMaskFragmentFunction
guard let drawOffscreenWithMaskPipelineState = try? device.makeRenderPipelineState(descriptor: drawOffscreenPipelineDescriptor) else {
preconditionFailure()
}
self.drawOffscreenWithMaskPipelineState = drawOffscreenWithMaskPipelineState
}
}