Metal图片置灰
这里通过在metal文件中进行设置的方式进行置灰
在正常流程的基础上增加了grayKernel函数,将输入的texture渲染为灰色输出到片段着色器中。
顶点函数的操作-》光栅化-〉片段函数的操作
在这里要传入片段函数的texture进行特殊的处理
constant half3 kRec709Luma = half3(0.2126, 0.7152, 0.0722); // 把rgba转成亮度值 kernel void grayKernel(texture2d<half, access::read> sourceTexture, texture2d<half, access::write> destTexture, uint2 grid[[thread_position_in_grid]]) { if (grid.x <= destTexture.get_width() && grid.y <= destTexture.get_height()) { half4 srcColor = sourceTexture.read(grid); half gray = dot(srcColor.rgb, kRec709Luma); destTexture.write(half4(gray, gray, gray, 1.0), grid); } }
如上将sourceTexture通过处理之后写入到destTexture中,在接下去的渲染中destTexture作为显示的texture
这里要注意的是grid[[thread_position_in_grid]]参数
1、grid指明了本次要进行处理的texture的位置
2、thread_position_in_grid则描述本线程所对应的grid位置
3、sourceTexture、destTexture分别指明的访问是read和write,在创建这两个texture的时候也要做对应的访问设置,如下标黄的设置;destTexture是读写都要,是因为在grayKernel需要使用写但是在fragmentShader则使用的是读
- (void)textureInit { UIImage* image = [UIImage imageNamed:@"abc.png"]; MTLTextureDescriptor* textureDesc = [[MTLTextureDescriptor alloc] init]; textureDesc.pixelFormat = MTLPixelFormatRGBA8Unorm; textureDesc.width = image.size.width; textureDesc.height= image.size.height; textureDesc.usage = MTLTextureUsageShaderRead; self.sourceTexture = [self.mtkView.device newTextureWithDescriptor:textureDesc]; Byte* imageBuffer = [self loadImage:image]; if (imageBuffer) { MTLRegion region = {{0, 0, 0}, {image.size.width, image.size.height, 1.0}}; [self.sourceTexture replaceRegion:region mipmapLevel:0 withBytes:imageBuffer bytesPerRow:image.size.width * 4]; free(imageBuffer); } textureDesc.usage = MTLTextureUsageShaderWrite | MTLTextureUsageShaderRead; self.destTexture = [self.mtkView.device newTextureWithDescriptor:textureDesc]; }
如下groupsize和groupcount分别指明了管道中每个线程要处理的texture的大小还有总共有groupcount个线程来处理
- (void)threadGridInit { self.groupSize = MTLSizeMake(16, 16, 1); _groupcount.width = (self.destTexture.width + self.groupSize.width - 1) / self.groupSize.width; _groupcount.height = (self.destTexture.height + self.groupSize.height - 1) / self.groupSize.height; _groupcount.depth = 1; }
{ id<MTLComputeCommandEncoder> computeEncoder = [commandBuffer computeCommandEncoder]; [computeEncoder setComputePipelineState:self.computePipeline]; [computeEncoder setTexture:self.sourceTexture atIndex:YCKernelIndexTextureInput]; [computeEncoder setTexture:self.destTexture atIndex:YCKernelIndexTextureOutput]; [computeEncoder dispatchThreadgroups:self.groupcount threadsPerThreadgroup:self.groupSize]; [computeEncoder endEncoding]; }
如上标黄的函数则是设置了要由多少个线程和每个线程处理多大的区域来执行grayKernel函数
要理解gpu多线程则需要对gpu有一定的了解,具体可看如下的链接
https://hustcat.github.io/gpu-architecture/
更详细的描述参考:https://www.jianshu.com/p/3e4acb8d36fd
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!