OpenGL

Metal Shading Language 语法规范

2020-11-17  本文已影响0人  Jeffery_zc

1. Metal Shading Language简介

Metal着色语言是用来编写3D图形渲染逻辑并行计算核心逻辑的一门编程语言,底层使用ClangLLVM进行编译处理。
Metal语言基于C++ 11.0 语言设计,我们主要用来编写在GPU上执行的图像渲染逻辑代码以及通用并行计算逻辑代码。当我们使用Metal框架来完成APP的实现时则需要使用Metal编程语言。

2. Metal 使用常识

2.1 Metal 与 C++ 11.0

Metal Restrictions 限制 (如下的C++11.0的特性在Metal 着色语言中是不支持的):

C++的标准库不可以在Metal 着色语言中使用。

2.2 Metal 语言中对于指针使用的限制

2.3 Metal 与OpenGL ES

3.0 Metal数据类型

类型 描述
bool 布尔类型,取值范围true,false;true可以拓展为整数常量1,false可以拓展为整数常量0
char 有符号8-bit整数
unsigned char (uchar) 无符号8-bit整数
short 有符号16-bit整数
unsigned short (ushort) 无符号16-bit整数
int 有符号32-bit整数
unsigned int (uint) 无符号32-bit整数
half 一个16-bit浮点数
float 一个32-bit浮点数
size-t 64-bit无符号整数,表示sizeof操作符的结果
ptrdiff_t 64-bit有符号整数,表示2个指针的差
void 表示一个空的值集合

3.1 Metal 向量和矩阵数据类型

3.1.1 向量

bool2 A= {1,2};
float4 pos = float4(1.0,2.0,3.0,4.0);
float x = pos[0];
float y = pos[1];

float4 VB;
for(int i = 0; i < 4 ; i++)
    VB[i] = pos[i] * 2.0f;


//通过向量字母来获取元素
int4 test = int4(0,1,2,3);
int a = test.x;
int b = test.y;
int c = test.z;
int d = test.w;

int e = test.r;
int f = test.g;
int g = test.b;
int h = test.a;

float4 c;
c.xyzw = float4(1.0f,2.0f,3.0f,4.0f);
c.z = 1.0f;
c.xy = float2(3.0f,4.0f);
c.xyz = float3(3.0f,4.0f,5.0f);


float4 pos = float4(1.0f,2.0f,3.0f,4.0f);
float4 swiz = pos.wxyz;  //swiz = (4.0,1.0,2.0,3.0);
float4 dup = pos.xxyy;  //dup = (1.0f,1.0f,2.0f,2.0f);

//pos = (5.0f,2.0,3.0,6.0)
pos.xw = float2(5.0f,6.0f);

//pos = (8.0f,2.0f,3.0f,7.0f)
pos.wx = float2(7.0f,8.0f);

//pos = (3.0f,5.0f,9.0f,7.0f);
pos.xyz = float3(3.0f,5.0f,9.0f);



float2 pos;
pos.x = 1.0f; //合法
pos.z = 1.0f; //非法

float3 pos2;
pos2.z = 1.0f; //合法
pos2.w = 1.0f; //非法

//非法,x出现2次
pos.xx = float2(3.0,4.0f);
//不合法-使用混合限定符
pos.xy = float4(1.0f,2.0,3.0,4.0);

float4 pos4 = float4(1.0f,2.0f,3.0f,4.0f);
pos4.x = 1.0f;
pos4.y = 2.0f;
//非法,.rgba与.xyzw 混合使用
pos4.xg = float2(2.0f,3.0f);
////非法,.rgba与.xyzw 混合使用
float3 coord = pos4.ryz;

float4 pos5 = float4(1.0f,2.0f,3.0f,4.0f);
//非法,使用指针来指向向量/分量
my_func(&pos5.xy);

3.1.2 矩阵

矩阵支持如下类型:

float4x4 m;
//将第二排的值设置为0
m[1] = float4(2.0f);

//设置第一行/第一列为1.0f
m[0][0] = 1.0f;

//设置第三行第四列的元素为3.0f
m[2][3] = 3.0f;

float4类型向量的所有可能构造方式

float4(float x);
float4(float x,float y,float z,float w);
float4(float2 a,float2 b);
float4(float2 a,float b,float c);
float4(float a,float2 b,float c);
float4(float a,float b,float2 c);
float4(float3 a,float b);
float4(float a,float3 b);
float4(float4 x);

float3类型向量的所有可能的构造的方式

float3(float x);
float3(float x,float y,float z);
float3(float a,float2 b);
float3(float2 a,float b);
float3(float3 x);

float2类型向量的所有可能的构造方式

float2(float x);
float2(float x,float y);
float2(float2 x);

4.纹理Texture类型

纹理类型是一个句柄,它指向一个一维/二维/三维纹理数据。
枚举值:定义了访问权限:

enum class access (sample,read,write);

sample:纹理对象可以被采样;
read:不使用采样器,一个图形渲染函数或者一个并行计算函数可以读取纹理对象;
write:一个图形渲染函数或者一个并行计算函数可以向纹理对象写入数据。

texture1d<T,access a = access::sample>
texture2d<T,access a = access::sample>
texture3d<T,access a = access::sample>

T:数据类型,设定了从纹理中读取或者是向纹理中写入时的颜色类型,T可以是half,float,short,int等。
举例

void foo (texture2d<float> imgA [[ texture(0) ]] ,texture2d<float, access::read> imgB [[ texture(1) ]], texture2d<float, access::write> imgC [[ texture(2) ]])
{ 
    ...
}

5. 采样器 Samples

采样器类型决定了如何对一个纹理进行采样操作。在Metal框架中有一个采样器对象MTLSamplerState,这个对象作为图形渲染着色器函数参数或者是并行计算函数的传递参数,也就是在sample中我们设置纹理的采样方式(环绕方式、过滤方式)。在Metal程序中初始化的采样器必须使用constexpr修饰符修饰

枚举名称(Enum Name) 有效值(Valid Value) 描述
coord normalized 从纹理中采样时,纹理坐标是否需要归一化
address clamp_to_edge,clamp_to_zero,mirrored_repeat,repeat 设置所有纹理坐标的寻址模式
s_address,t_address,r_address clamp_to_edge,clamp_to_zero,mirrored_repeat,repeat 设置某个纹理坐标的寻址模式
filter nearest,linear 设置纹理采样的放大和缩小的过滤模式
mag_filter nearest,linear 设置纹理采样的放大过滤模式
min_filter nearest,linear 设置纹理采样的缩小过滤模式
mip_filter none,nearest,linear 设置纹理采样的minmap过滤模式,如果是none,那么只有一个层纹理能生效
compare_func none,less,less_qual,greater,greater_equal,equal,not_equal 为使用r纹理坐标做shaw map,设置比较测试逻辑,这个状态值的设置只可以在Metal着色语言程序中完成

从纹理中采样时,纹理坐标是否需要归一化

enum class coord {noramlized,pixel };

纹理采样过滤方式,放大/缩小过滤模式

enum class filter {nearest, linear};

设置纹理采样缩小过滤模式

enum class min_filter {nearest, linear};

设置纹理采样放大过滤模式

enum class mag_filter {nearest, linear};

设置s,t,r纹理坐标的寻址模式

enum class s_address{clamp_to_zero,clamp_to_edge,repeat,mirrored_repeat };
enum class t_address{clamp_to_zero,clamp_to_edge,repeat,mirrored_repeat };
enum class r_address{clamp_to_zero,clamp_to_edge,repeat,mirrored_repeat };

设置所有纹理坐标的寻址模式

enum class address{clamp_to_zero,clamp_to_edge,repeat,mirrored_repeat };

例:

constexpr samper s(coord::pixel,address::clamp_to_zero,filter::linear);

6. 函数修饰符

kernel void test(...)
{
    ......
}
kernel void test1(...)
{
}
vertex float4 test2(...)
{
  test1(...); // 这个是错误的调用
}

7. 地址空间修饰符

地址空间修饰符,是Metal着色语言用来给参数变量或者函数变量分配内存使用的。所有的着色函数(kernel,vertex,fragment)的参数,如果是指针或者是引用,都必须带有地址空间修饰符。

device float4 *color;
struct test{
 float a[2];
int b[1];
}
device test *info;

注意:纹理对象总是在设备地址空间分配内存,device地址空间修饰符不必出现在纹理类型定义中,一个纹理对象的内容无法直接访问,可使用Metal自身的内建函数

kernel void func(threadgroup float *a[[threadgroup(0)]])
{
    ....
}
constant float samples[] = {1.0f,2.0f,3.0f,4.0f};
samples[4] = {3,2,3,2}; //编译失败,因为constant是只读的
constant float a; // 编译失败,因为没有赋值
kernel void func(...)
{
  float x;
  thread float p = &x;
  ...
}

对于图形着色函数,其指针或是引用类型的参数必须定义为device或者是constant地址空间,对于并行计算着色函数,其指针或是引用类型的参数必须定义为device或者是constant或者是threadgroup地址空间

8. 函数参数与变量

图形绘制或者并行计算着色器函数的输入输出都是通过参数传递,除了常量地址空间变量和程序域定义的采样器除外。

对于每个着色器函数来说,一个修饰符是必须指定的,他用来设定一个缓存,纹理,采样器的位置。

kernel void add_vectros(
                const device float4 *inA [[buffer(0)]],
                const device float4 *inB [[buffer(1)]],
                device float4 *out [[buffer(2)]]
                uint id[[thread_position_in_grid]])
{
    out[id] = inA[id] + inB[id];
}
thread_position_in_grid:用于表示当前节点在多线程网格中的位置;

内建变量属性修饰符

struct myFragmentOutput{
    float4 cl_f[[color(0)]];
    float4 cl_i[[color(1)]];
    float4 cl_u[[color(2)]];
};

fragment myFragmentOutput shader()
{
    myFragmentOutput f;
    f.cl_f = ...;
    ...
    return f;
}

属性修饰符目的:

  1. 参数表示资源如何定位? 可以理解为端口;
  2. 在固定管线和可编程管线进行内建变量的传递;
  3. 将数据沿着渲染管线从顶点函数传递片元函数。
上一篇下一篇

猜你喜欢

热点阅读