一、基本Metal概念
Metal是iOS推出的图像渲染工具,类似于OpenGL,Metal为图形和数据并行计算工作负载提供单一,统一的编程接口和语言。 Metal使您能够更有效地集成图形和计算任务,而无需使用单独的API和着色器语言。
Metal框架提供以下内容:
- Low-overhead interface - 低开销接口。 Metal旨在消除“隐藏”性能瓶颈,例如隐式状态验证。您可以控制GPU的异步行为,以实现用于并行创建和提交命令缓冲区的高效多线程。
有关Metal命令提交的详细信息,请参阅Command Organization and Execution Model。
- Memory and resource management - 内存和资源管理。 Metal框架描述了表示GPU内存分配的缓冲区和纹理对象。纹理对象具有特定的像素格式,可用于纹理图像或附件。
有关Metal内存对象的详细信息,请参阅Resource Objects: Buffers and Textures。
- Integrated support for both graphics and compute operations - 集成了对图形和计算操作的支持。 Metal为图形和计算操作使用相同的数据结构和资源(如缓冲区,纹理和命令队列)。此外,Metal着色语言支持图形和计算函数。 Metal框架允许在运行时接口,图形着色器和计算函数之间共享资源。
有关编写使用Metal进行图形渲染或数据并行计算操作的应用程序的详细信息,请参阅Graphics Rendering: Render Command Encoder或Data-Parallel Compute Processing: Compute Command Encoder。
- Precompiled shaders - 预编译着色器。可以在构建时编译Metal着色器以及应用程序代码,然后在运行时加载。此工作流程提供了更好的代码生成以及更简单的着色器代码调试。 (Metal还支持着色器代码的运行时编译。)
有关使用Metal框架代码中的Metal着色器的详细信息,请参阅Functions and Libraries。有关Metal Shading Language Guide
本身的详细信息,请参见Metal Shading Language Guide
。
二、创建连接Metal文件
1、创建metal文件第一步要获取Metal设备就是手机等设备、获取命令队列
init(){ guard let device = MTLCreateSystemDefaultDevice() else{ fatalError("Could not create Metal Device") } self.device = device guard let queue = self.device.makeCommandQueue() else{ fatalError("Could not create command queue") } self.commandQueue = queue // let frameworkBundle = Bundle.main // guard let metalLibraryPath = frameworkBundle.path(forResource: "default", ofType: "metallib")else{ // fatalError("Could not load library") // } do { self.shaderLibrary = try device.makeDefaultLibrary(bundle: Bundle.main) } catch { fatalError("Could not load library") } }
2、创建metal文件、编写着色器代码
编写顶点着色器和片元着色器代码
// // BlendModeConstants.metal // DQVideoEditor // // Created by zhaoquan.du on 2022/9/26. // #include <metal_stdlib> #include "OperationShaderTypes.h" #include "BlendModeConstants.h" using namespace metal; vertex SingleInputVertexIO blendOperationVertex(const device packed_float2 *position [[ buffer(0) ]], const device packed_float2 *texturecoord [[ buffer(1) ]], constant float4x4& modelView [[ buffer(2) ]], constant float4x4& projection [[ buffer(3) ]], uint vid [[vertex_id]]) { SingleInputVertexIO outputVertices; outputVertices.position = projection * modelView * float4(position[vid], 0, 1.0); outputVertices.textureCoordinate = texturecoord[vid]; return outputVertices; } half4 normalBlend(half3 Sca, half3 Dca, half Sa, half Da) { half4 blendColor; blendColor.rgb = Sca + Dca * (1.0 - Sa); blendColor.a = Sa + Da - Sa * Da; return blendColor; } half4 darken(half3 Sca, half3 Dca, half Sa, half Da) { half4 blendColor; blendColor.rgb = min(Sca * Da, Dca * Sa) + Sca * (1.0 - Da) + Dca * (1.0 - Sa); blendColor.a = Sa + Da - Sa * Da; return blendColor; } half4 multiply(half3 Sca, half3 Dca, half Sa, half Da) { half4 blendColor; blendColor.rgb = Sca * Dca + Sca * (1.0 - Da) + Dca * (1.0 - Sa); blendColor.a = Sa + Da - Sa * Da; return blendColor; } fragment half4 blendOperationFragment(SingleInputVertexIO fragmentInput [[stage_in]], texture2d<half> inputTexture [[texture(0)]], half4 backColor [[color(0)]], constant int& blendMode [[ buffer(1) ]], constant float& blendOpacity [[ buffer(2) ]]) { constexpr sampler quadSampler; half4 sourceColor = inputTexture.sample(quadSampler, fragmentInput.textureCoordinate); half3 Sca = sourceColor.rgb; half3 Dca = backColor.rgb; half Sa = sourceColor.a; half Da = backColor.a; half4 blendColor; if (blendMode == BlendModeNormal) { blendColor = normalBlend(Sca, Dca, Sa, Da); } else if (blendMode == BlendModeDarken) { blendColor = darken(Sca, Dca, Sa, Da); } else if (blendMode == BlendModeMultiply) { blendColor = multiply(Sca, Dca, Sa, Da); } else { blendColor = half4(0.0, 0.0, 0.0, 1.0); } return mix(backColor, blendColor, blendOpacity); }
3.创建渲染管道,保存着色器参数类型
func generateRenderPipelineState(vertexFunctionName:String, fragmentFunctionName:String, oprationName:String) -> (MTLRenderPipelineState, [String: UniformInfor], [String: UniformInfor]){ //获取顶点着色器函数 guard let vertexFunction = sharedMetalRenderingDevice.shaderLibrary.makeFunction(name: vertexFunctionName) else{ fatalError("\(oprationName):could not compile vertex function \(vertexFunctionName)") } //获取片元着色器函数 guard let fragmentFuntion = sharedMetalRenderingDevice.shaderLibrary.makeFunction(name: fragmentFunctionName) else{ fatalError("\(oprationName): could not compile fragment function \(fragmentFunctionName)") } //配置渲染管道描述符 let descriptor = MTLRenderPipelineDescriptor() descriptor.colorAttachments[0].pixelFormat = MTLPixelFormat.bgra8Unorm descriptor.rasterSampleCount = 1 descriptor.vertexFunction = vertexFunction descriptor.fragmentFunction = fragmentFuntion do { //创建渲染管道 var reflection: MTLAutoreleasedRenderPipelineReflection? let pipLinState = try sharedMetalRenderingDevice.device.makeRenderPipelineState(descriptor: descriptor,options: [.bufferTypeInfo, .argumentInfo],reflection: &reflection) //获取着色器函数 参数类型,以便之后传惨 var vertexUniforms: [String: UniformInfor] = [:] var fragmentUniforms = [String : UniformInfor]() if #available(iOS 16.0, *) { if let vertexBudings = reflection?.vertexBindings as? [MTLBufferBinding]{ for bufferBuding in vertexBudings { let uniformInfor = UniformInfor(locationIndex: bufferBuding.index, dataSize: bufferBuding.bufferDataSize) vertexUniforms[bufferBuding.name] = uniformInfor } } //片元着色器中参数 banging中有 MTLTextureBinding 和 MTLBufferBinding,需要过滤一下 if let fragmentBudings = reflection?.fragmentBindings.compactMap({$0 as? MTLBufferBinding}) as? [MTLBufferBinding]{ for bufferBuding in fragmentBudings { let uniformInfor = UniformInfor(locationIndex: bufferBuding.index, dataSize: bufferBuding.bufferDataSize) fragmentUniforms[bufferBuding.name] = uniformInfor } } } else { if let vertexArguments = reflection?.vertexArguments { for vertexArgument in vertexArguments where vertexArgument.type == .buffer { let uniformInfor = UniformInfor(locationIndex: vertexArgument.index, dataSize: vertexArgument.bufferDataSize) vertexUniforms[vertexArgument.name] = uniformInfor } } if let fragmentArguments = reflection?.fragmentArguments { for fragmentArgument in fragmentArguments where fragmentArgument.type == .buffer { let uniformInfor = UniformInfor(locationIndex: fragmentArgument.index, dataSize: fragmentArgument.bufferDataSize) fragmentUniforms[fragmentArgument.name] = uniformInfor } } } return (pipLinState, vertexUniforms, fragmentUniforms) } catch { fatalError("Could not create render pipeline state for vertex:\(vertexFunctionName), fragment:\(fragmentFunctionName), error:\(error)") } }
标签:blendColor,渲染,Metal,Da,let,Sa,Swift,着色器 From: https://www.cnblogs.com/duzhaoquan/p/16772428.html