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

 

posted @   LCAC  阅读(90)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
点击右上角即可分享
微信分享提示