Metal图片置灰
这里通过在metal文件中进行设置的方式进行置灰
在正常流程的基础上增加了grayKernel函数,将输入的texture渲染为灰色输出到片段着色器中。
顶点函数的操作-》光栅化-〉片段函数的操作
在这里要传入片段函数的texture进行特殊的处理
constant half3 kRec709Luma = half3(0.2126, 0.7152, 0.0722); // 把rgba转成亮度值 kernel void grayKernel(texture2dsourceTexture, texture2d 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; }
{ idcomputeEncoder = [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