mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-15 21:45:19 +00:00
209 lines
12 KiB
Swift
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
|
|
}
|
|
}
|
|
|