Metal渲染:Metal Shading Language兼容性问题

 本文主要记录几种在工作中遇到的由于Metal Shading Language兼容导致的问题。

一、请一定动态方式创建Shader Library

  系统提供了两种方式创建shader library:

  • 能过MTLDevice以下接口使用Xcode提前编译好的.metallib文件
/*!
 @method newLibraryWithFile:
 @abstract Load a MTLLibrary from a metallib file.
 */
- (nullable id <MTLLibrary>)newLibraryWithFile:(NSString *)filepath error:(__autoreleasing NSError **)error;
  • 通过MTLDevice的接口使用shader的源码在运行时进行编译创建,在第一次创建library时需要进行编译,所以创建livbrary比编译好的.metallib文件稍微耗时一多一点
- (nullable id <MTLLibrary>)newLibraryWithSource:(NSString *)source
                                         options:(nullable MTLCompileOptions *)options
                                           error:(__autoreleasing NSError **)error;

在项目中我最初也由于想当然的认为苹果的兼容性比较好,只要Metal Shading Language使用的版本一致,满足系统版本要求,不会有兼容问题,使用了提前由Xcode编译好的.metallib文件创建MTLLibrary,但被事实打脸。所以在此建议大家使用源码在目标机上运行创建MTLLibrary。

 

二、使用源码在目标机器上运行时进行编译创建MTLLibrary,其编译对C/C++语法要求更严格。

2.1 在Xcode中编译的.metal源码中我们可以这样定义一个全局变量:

static constant float3x3 Primaries2020to709 =
{
    float3(1.66049623f, -0.58765644f, -0.07283977f),
    float3(-0.12454709f,  1.13289511f, -0.00834801f),
    float3(-0.01815368f, -0.10059737f,  1.11875105f)
};

但是如果你把这个定义使用源码在运行时进行编译创建MTLLibrary会得到如下错误:

 

 

 

编译器找不到这种创建float3x3矩阵的构造器,但是使用Xcode编译时,能编译过。因此只能更改为如下方式:

static constant float3x3 Primaries2020to709 =
{
    1.66049623f, -0.58765644f, -0.07283977f,
    -0.12454709f,  1.13289511f, -0.00834801f,
    -0.01815368f, -0.10059737f,  1.11875105f
};

 

2.2 我们知道在Objective-C文件中,可以不用声明方法/函数,就可以在一个方法定义中使用另一个方法,使用Xcode编译.metal源码也是一样,如下代码是可以编译通过的:

float4 convert_hdr_yuv_to_rgba_for_edr(float3 yuv, /* 其它参数,为防泄密不放出来 */) {

       .......
       return hdrrgba; 
}

float4 deal_with_sampled_yuv(float3 yuv, float2 textureCoordinate,  /* 其它参数,为防泄密不放出来 */) {

   ......
    
    float4 hdr = convert_hdr_yuv_to_rgba_for_edr(yuv,  /* 其它参数,为防泄密不放出来 */);
    return hdr;
}

但当使用Metal Shader源码在目标机器上创建MTLLibrary时会出现如下错误:

 

解决办法是:

  1. 在函数定义前先增加一个声明
  2. 将函数声明为static或者inline
  3. 将函数包在匿名namespace内

我的解决办法是定义为inline函数。

 

三、最后是一个系统及设备(2016版本Macbook + 10.11.6系统)出现的一个匪夷所思的问题:设备上渲染出来后无彩色,画面全部黑白的问题。

涉及目前公司项目原因,略去求证解决过程直接上结果

在Metal Shading Language Specification中关于saturate函数的说明如下

 

saturate就是将输入裁剪限定在0.0到1.0的一个闭区间(如果输入小于0.0,则输出0; 如果输入大于1.0,则输出1.0)。并且此方法是一个模板方法,如果输入一个数组,则会对数组的每一个元素做[0,0 1.0]的裁剪。但是很遗憾的是我们在2016版Macbook + macOS 10.11.6系统上发现,将rgba数组用saturate处理后,输出的数组各分量的值完全相等了,因此我们会得到一张黑白的画面。

这真的是一个很让人不敢怀疑的问题,最后二分法回退git提交,一步步回退代码,验证发现确实是苹果的这样一个基础的方法出了BUG,简直如同绝对值函数给你返回一个负数一样不可思议。

解决方法很简单,不要用saturate处理容器,只用来处理单个的数了😫

 

posted on 2020-05-05 13:11  课蜜黄蜂  阅读(652)  评论(0编辑  收藏  举报