注册

iOS Metal语言规范浅谈

一.Metal简述

            Metal着色器语言是用来编写3D图形渲染逻辑、并行Metal计算核心逻辑的一门编程语言,当你使用Metal框架来完成APP的实现时则需要使用Metal编程语言。

            Metal语言使用Clang 和LLVM进行编译处理,编译器对于在GPU上的代码执行效率有更好的控制

            Metal基于C++ 11.0语言设计的,在C++基础上多了一些扩展和限制,主要用来编写在GPU上执行的图像渲染逻辑代码以及通用并行计算逻辑代码

            Metal 像素坐标系统:Metal中纹理 或者 帧缓存区attachment的像素使用的坐标系统的原点是左上角

1.1Metal 语⾔中不⽀持之处 

        Lambda 表达式;

        递归函数调⽤

        动态转换操作符

        类型识别

        对象创建new 和销毁delete 操作符;

        操作符 noexcept

        goto 跳转

        变量存储修饰符register 和 thread_local;

        虚函数修饰符;

        派⽣类

        异常处理

        C++ 标准库在Metal 语⾔中也不可使⽤;

1.2Metal 语⾔中对于指针使⽤的限制

        Metal图形和并⾏计算函数⽤到的⼊参数; 如果是指针必须使⽤地址空间修饰符(device,threadgroup,constant)

        不⽀持函数指针;

        函数名不能出现main

二.Metal的数据类型及语法

2.1     Metal 数据类型--标量数据类型 

        bool 布尔类型, true/false

        char 有符号8位整数;

        unsigned char /uchar ⽆符号8-bit 整数;

        short 有符号16-bit整数;

        unsigned short / ushort ⽆符号32-bit 整数;

        half 16位bit 浮点数;

        float 32bit 浮点数;

        size_t 64 ⽆符号整数;

        void 该类型表示⼀个空的值集合

说明:其中half 相当于OC中的float,float 相当于OC中的doublesize_t用来表示内存空间, 相当于 OC中 sizeof

示例:boola=true;charb=5;intd=15;//用于表示内存空间size_t c=1;ptrdiff_t f=2;

2.2Metal向量

        向量支持如下类型:- booln、charn、shortn、intn、ucharn、ushortn、uintn、halfn、floatn,其中 n 表示向量的维度,最多不超过4维向量示例:

        //直接赋值初始化

        bool2 A={1,2}

        ;//通过内建函数float4初始化

        float4 pos=float4(1.0,2.0,3.0,4.0);

        //通过下标从向量中获取某个值

        floatx=pos[0];floaty=pos[1];

        //通过for循环对一个向量进行运算

        float4 VB;

        for(inti=0;i<4;i++){

            VB[i]=pos[i]*2.0f;

        }

        说明:在OpenGL ES的GLSL语言中,例如2.0f,在着色器中书写时,是不能加f,写成2.0,而在Metal中则可以写成2.0f,其中f可以是大写,也可以是小写

向量的访问规则:

1.通过向量字母获取元素: 向量中的向量字母仅有2种,分别为xyzw、rgba

        int4 test=int4(0,1,2,3);

        inta=test.x; //获取的向量元素0

        intb=test.y; //获取的向量元素1

        intc=test.z; //获取的向量元素2

        intd=test.w;//获取的向量元素3

        inte=test.r; //获取的向量元素0

        intf=test.g;//获取的向量元素1

        intg=test.b; //获取的向量元素2

        inth=test.a; //获取的向量元素3

2.多个分量同时访问

        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);

        说明:赋值时分量不可重复,取值时分量可重复右边是取值 和 左边赋值都合法xyzw与rgba不能混合使用,GLSL中向量不能乱序访问,只是和Metal中的向量相似,并不是等价

6232b9594b451e67243f8fdaeb5f8547.png

2.3矩阵

        矩阵支持如下类型- halfnxm、floatnxm,其中 nxm表示矩阵的行数和列数,最多4行4列,其中half、float相当于OC中的float、double- 普通的矩阵其本质就是一个数组

        float4x4 m;

        //将第二行的所有值都设置为2.0

        m[1]=float4(2.0f);

        //设置第一行/第一列为1.0f

        m[0][0]=1.0f;

        //设置第三行第四列的元素为3.0f

        m[2][3]=3.0f;

        float4 类型向量的构造方式

        1个float构成,表示一行都是这个值

        4个float构成

        2个float2构成

        1个float2+2个float构成(顺序可以任意组合)

        1个float2+1个float

        1个float4

eg:

        //float4类型向量的所有可能构造方式//1个一维向量,表示一行都是xfloat4(floatx);

        ///4个一维向量 --> 4维向量float4(floatx,floaty,floatz,floatw);

        //2个二维向量 --> 4维向量float4(float2 a,float2 b);

        //1个二维向量+2个一维向量 --> 4维向量float4(float2 a,float b,float c);

        float4(floata,float2 b,floatc);float4(floata,floatb,float2 c);

        //1个三维向量+1个一维向量 --> 4维向量float4(float3 a,floatb);float4(floata,float3 b);

//1个四维向量 --> 4维向量float4(float4 x);

float3 类型向量的构造方式

        1个float构成,表示一行都是这个值

        3个float

        1个float+1个float2(顺序可以任意组合)

        1个float2

eg:

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

        //1个一维向量float3(floatx);

        //3个一维向量float3(floatx,floaty,floatz);

        //1个一维向量 + 1个二维向量float3(floata,float2 b);

        /1个二维向量 + 1个一维向量float3(float2 a,floatb);

        //1个三维向量float3(float3 x);

        float2 类型向量的构造方式

 1个float构成,表示一行都是这个值

        2个float

        1个float2

eg:

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

        //1个一维向量float2(floatx);

        //2个一维向量float2(floatx,floaty);

        //1个二维向量float2(float2 x);

三,Metal的其他类型


1.纹理

纹理类型

纹理类型是一个句柄,指向一维/二维/三维纹理数据,而纹理数据对应一个纹理的某个level的mipmap的全部或者一部分

纹理的访问权限

在一个函数中描述纹理对象的类型

access枚举值由Metal定义,定义了纹理的访问权利enum class access {sample, read, write};,有以下3种访问权利,当没写access时,默认的access 就是sample

sample: 纹理对象可以被采样(即使用采样器去纹理中读取数据,相当于OpenGL ES的GLSL中sampler2D),采样一维这时使用 或者 不使用都可以从纹理中读取数据(即可读可写可采样)

read:不使用采样器,一个图形渲染函数或者一个并行计算函数可以读取纹理对象(即仅可读)

write:一个图形渲染函数 或者 一个并行计算可以向纹理对象写入数据(即可读可写)

定义纹理类型

描述一个纹理对象/类型,有以下三种方式,分别对应一维/二维/三维,

其中T代表泛型,设定了从纹理中读取数据 或是 写入时的颜色类型,T可以是half、float、short、int等

access表示纹理访问权限,当access没写时,默认是sample

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

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

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

eg:

//类型 变量 修饰符

/*

类型

    - texture2d<float>,读取的数据类型是float,没写access,默认是sample

    - texture2d<float,access::read>,读取的数据类型是float,读取的方式是read

    - texture2d<float,access::write>,读取的数据类型是float,读取的方式是write

变量名

    - imgA

    - imgB

    - imgC

修饰符

    - [[texture(0)]] 对应纹理0

    - [[texture(1)]] 对应纹理1

    - [[texture(2)]] 对应纹理2

*/函数举例

void foo (texture2d<float> imgA[[texture(0)]],

          texture2d<float,access::read> imgB[[texture(1)]],

          texture2d<float,access::write> imgC[[texture(2)]])

{

    //...

}

2.采样器

        采样器类型决定了如何对一个纹理进行采样操作,在Metal框架中有一个对应着色器语言的采样器的对象MTLSamplerState,这个对象作为图形渲染着色器函数参数或是并行计算函数的参数传递,有以下几种状态:

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

enum class coord { normalized, pixel };

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

enum class filter { nearest, linear };

min_filter:设置纹理采样的缩小过滤方式

enum class min_filter { nearest, linear };

mag_filter:设置纹理采样的放大过滤方式

enum class mag_filter { nearest, linear };

s_address、t_address、r_address:设置纹理s、t、r坐标(对应纹理坐标的x、y、z)的寻址方式

s坐标:enum class s_address { clamp_to_zero, clamp_to_edge, repeat, mirrored_repeat };

t坐标:enum class t_address { clamp_to_zero, clamp_to_edge, repeat, mirrored_repeat };

r坐标:enum class r_address { clamp_to_zero, clamp_to_edge, repeat, mirrored_repeat };

address:设置所有纹理坐标的寻址方式

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

mip_filter:设置纹理采样的mipMap过滤模式, 如果是none,那么只有一层纹理生效;

enum class mip_filter { none, nearest, linear };


50958b35c13e377601fe91303d151640.png


作者:枫紫_6174
链接:https://www.jianshu.com/p/17baccd48e77









0 个评论

要回复文章请先登录注册