标量数据类型 - Scalar Data Types
Metal不支持这些数据类型:double, long, unsigned long, long long, unsigned long long, long double。
支持以下类型及其描述:
bool - 布尔数据类型,取值有true或false,true可以扩展为整数常量1,false可以扩展为整数常量0
har/int8_t - 有符号8-bit整型
unsigned char/uchar/uint8_t - 无符号8-bit整型
short/int16_t - 有符号16-bit整型
unsigned short/ushort/uint16_t - 无符号16-bit整型
int/int32_t - 有符号32-bit整型
unsigned int/ uint/ uint32_t - 无符号32-bit整型
half - 一个16-bit浮点数
float - 一个32-bit浮点数
size_t - 一个16-bit浮点数
ptrdiff_t - 64-bit有符号整数,表示两个指针的差
void - 该类型表示一个空的值集合
MSL支持使用下面的后缀用来表示字面量类型
f或是F用来表示单精度浮点型字面量(比如 0.5f 或是 0.5F)
h或是H用来表示半单精度浮点型字面量(比如0.5h 或是0.5H)
u或是U用来表示无符号整形字面量。
标量数据类型的大小和对齐方式:
向量数据类型 - Vector and Matrix Data Types
Metal着色语言通过系统向量数学库支持一系列的向量和矩阵数据类型。
Metal支持的向量类型名如下:
booln, charn, shortn, intn, ucharn, ushortn, uintn, halfn, floatn
n的取值为2,3或是4,分别表示一个2维,3维或是4维向量类型。
向量数据类型的大小和对齐方式:
如何访问向量
向量的分量可以使用数组下标进行访问存取。数组下标0引用了向量的第一个分量,数组下标1引用了向量的第二个分量,以此类推
示例:
pos = float4(1.0f, 2.0f, 3.0f, 4.0f);
float x = pos[0]; // x = 1.0
float z = pos[2]; // z = 3.0
float4 vA = float4(1.0f, 2.0f, 3.0f, 4.0f);
float4 vB;
for (int i = 0; i < 4; i++) {
// vB = (2.0, 4.0, 6.0, 8.0);
vB[i] = vA[i] * 2.0f
}
Metal支持使用(.)作为选择向量分量进行访问的操作符,可以使用表示坐标分量或是颜色分量的字母来存取向量: 向量名.xyzw 或是 向量名.rgba。
示例:
int4 test = int4(0, 1, 2, 3);
int a = test.x; // a=0
int b = test.y; // b=1
int c = test.z; // c=2
int d = test.w; // d=3
int e = test.r; // e=0
int f = test.g; // f=1
int g = test.b; // g=2
int h = test.a; // h=3
分量选择语法允许多个分量同时被选择访问。如下面的例子所示:
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.wzyx; // swiz = (4.0f, 3.0f, 2.0f, 1.0f)
float4 dup = pos.xxyy; // dup = (1.0f, 1.0f, 2.0f, 2.0f)
向量的分量组标记可以出现在表达式的左边,表示左值,乱序的分量也是支持的。左值可以是标量或是向量,这取决于被指定的分量的个数。每一个分量必须是一个被支持的标量或是向量类型。作为左值,不可以包含重复分量。 以上描述的规则如下面的例子所示:
float4 pos = float4(1.0f, 2.0f, 3.0f, 4.0f); // pos = (5.0, 2.0, 3.0, 6.0)
pos.xw = float2(5.0f, 6.0f);
// pos = (8.0, 2.0, 3.0, 7.0) pos.wx = float2(7.0f, 8.0f);
// pos = (3.0, 5.0, 9.0, 7.0) pos.xyz = float3(3.0f, 5.0f, 9.0f);
如下的向量分量访问方法是不被允许会导致编译错误:
1、访问向量分量时,如果超过了向量声明的维度数会产生错误。一个2维向量可以通过 .xy 或 .rg 访问其分量。一 个3维的向量可以通过 .xyz 或 .rgb 访问其分量,如下面的例子所示:
float2 pos;
pos.x = 1.0f; // is legal; so is y
pos.z = 1.0f; // is illegal; so is w
float3 pos;
pos.z = 1.0f; // is legal
pos.w = 1.0f; // is illegal
2、如果作为左值,同一个分量出现多于一次是错误的,如下例所示:
// illegal - 'x' used twice
pos.xx = float2(3.0f, 4.0f);
// illegal - mismatch between float2 and float4
pos.xy = float4(1.0f, 2.0f, 3.0f, 4.0f);
3、.rbga 和 .xyzw 不能在同一次访问中混用,如下例所示:
.rbga 和 .xyzw 不能在同一次访问中混用,如下例所示:
float4 pos = float4(1.0f, 2.0f, 3.0f, 4.0f);
pos.x = 1.0f; // OK
pos.g = 2.0f; // OK
pos.xg = float2(3.0f, 4.0f); // illegal - mixed qualifiers used float3 coord = pos.ryz; // illegal - mixed qualifiers used
4、指向向量分量的指针或是引用也是不合法的。如下例所示:
float4 pos = float4(1.0f, 2.0f, 3.0f, 4.0f);
my_func(&pos.xy); // This is an illegal pointer to a swizzle.
sizeof 操作符号返回向量的尺寸,这个尺寸等于向量分量的数量 * 每个分量的尺寸。比如sizeof(float4)返回16,而 sizeof(half4) 返回8。
向量的构造
构造器可以用一组标量或是向量来构造向量。当一个向量被初始化,参数签名决定了它如何被构造。比如,如果向量的构造只使用一个标量作为参数,那么这个向量所有的分量都被设置为这个标量的值。
如过构造向量时,使用多个标量,一个或是多个向量,或是标量和向量的混合,那么向量的构造就按照参数出现的 顺序。构造时,参数从左到右被使用。每个参数所有的分量都被按顺序读取。
如下是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, float b, float2 c);
float4(float a, float2 b, float 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);
下面的例子展示了多个向量构造器的实际使用:
float x = 1.0f, y = 2.0f, z = 3.0f, w = 4.0f;
float4 a = float4(0.0f);
float4 b = float4(x, y, z, w);
float2 c = float2(5.0f, 6.0f);
float2 a = float2(x, y);
float2 b = float2(z, w);
float4 x = float4(a.xy, b.xy);
如果构造器参数不足会产生编译时错误。
紧密填充向量类型 - Packed Vector Data Types
向量数据类型都是按照其尺寸对齐的,但是会出现一些情况,开发者需要将向量数据紧密填充。比如,一个顶点数 据结构可能由位置、法向量、正切向量和纹理坐标紧密填充并且以缓存方式传递给一个顶点计算着色函数。
紧密填充向量类型支持如下这些:
packed_charn, packed_shortn, packed_intn, packed_ucharn, packed_ushortn, packed_uintn, packed_halfn, packed_floatn。
其中n可以是2,3,或是4,代表2维、3维、4维类型向量。(packed_booln被保留不可用)。
表2-5列举了紧密填充类型向量的对齐和尺寸。
**注:紧密填充类型的对齐方式并非全为2的n次方
**
紧密填充向量通常用于数据存储格式。载入和存储紧密填充类型向量到一个对齐向量或是反之,都有相应拷贝构造和赋值操作符支持。各算术、逻辑和关系运算符也都支持紧密填充类型向量。
Example:
device float4 *buffer;
device packed_float4 *packed_buffer;
int i;
packed_float4 f ( buffer[i] );
pack_buffer[i] = buffer[i];
// operator to convert from packed_float4 to float4.
buffer[i] = float4( packed_buffer[i] );
可以使用数组下标语法来访问紧密填充类型向量的分量,但是不支持使用.xyzw 和 .rgba语法来访问紧密填充类型向 量的分量。
Example:
packed_float4 f;
f[0] = 1.0f; // OK
f.x=1.0f; //Illegal-compilationerror
矩阵数据类型 - Matrix Data Types
Metal支持的矩阵类型名如下:
1、 halfnxm
2、floatnxm
**n和m分别表示矩阵列数和行数,n和m可以是2,3或是4。
**
一个矩阵被看做是由几个向量构成
比如一个floatnx3的矩阵由n个float3类型向量构成。类似的一个halfnx4矩阵由n个half4类型向量构成。
矩阵数据类型的大小和对齐方式:
访问矩阵分量-Accessing Matrix Data Type
floatnxm可以被当做一个有n个floatm向量构成的数组来访问,halfnxm可以被当做一个有n个halfm向量构成的数组来访问。
矩阵的各分量可以使用数组下标语法来访问。如果只使用一个数组下标访问矩阵,那么数组就是被当做列向量数组被访问,第一列的下标是0。如果有第二个下标,那么表示访问列向量内的某个分量,也就是说两个下标先选择了列 后选择行。下面就是使用数组下标访问矩阵分量的示例:
float4x4 m;
// This sets the 2nd column to all 2.0.
m[1] = float4(2.0f);
// This sets the 1st element of the 1st column to 1.0. m[0][0] = 1.0f;
// This sets the 4th element of the 3rd column to 3.0. m[2][3] = 3.0f;
如果使用一个非常量的表达式作为下标访问矩阵分量越界,那么这个访问行为未知。如果使用一个常量表达式作为下标访问矩阵分量越界,那么将产生一个编译时错误。
矩阵的构造-Matrix Constructors
矩阵构造器可以使用一组标量、向量、或是矩阵来创建新矩阵。
当矩阵被初始化,构造器的参数签名决定矩阵如何 被构造。比如,如果一个矩阵只使用一个标量初始化,那么构造出来的矩阵的对角线上的分量被赋值成这个标量的 值,其他的矩阵分量被设置为0.0,如下例所示:
float4x4(fval);
fval是一个标量浮点数,那么构造出来的矩阵的各分量如下所示:
fval 0.0 0.0 0.0
0.0 fval 0.0 0.0
0.0 0.0 fval 0.0
0.0 0.0 0.0 fval
一个矩阵也可以由另一个有同样尺寸(也就是有相同的行数和列数)的矩阵构造,比如:
float3x4(float3x4);
float3x4(half3x4);
如上从另一个矩阵构造新矩阵的情况下,矩阵的各分量将以列主序来构造。作为参数矩阵必须要有足够的分量来构 造新矩阵的每一个分量,供了过多的分量(参数矩阵的尺寸比构造矩阵大)会导致编译错误。如果参数矩阵的分 量个数不足用来初始化(参数矩阵的尺寸比构造矩阵小)也会导致编译错误。
一个T类型的n列m行的矩阵可以被n个T类型的m维向量初始化。下面的例子都是合法的初始化:
float2x2(float2, float2);
float3x3(float3, float3, float3);
float3x2(float2, float2, float2);
如下面的例子中的矩阵的构造是不支持的。一个矩阵不支持从多个标量构造,也不支持标量和向量混合构造。
// both cases below are not supported
float2x2(float a00, float a01, float a10, float a11);
float2x3(float2 a, float b, float2 c, float d);
##Alignment of Data Types - 数据对齐
数据对齐 - Alignment of Data Types
对齐说明符:alignas
可以使用对齐说明符(alignas)指定类型或对象的对齐要求。还可以将对齐说明符(alignas)应用于结构或类的变量或数据成员的声明。还可以将其应用于结构、类或枚举类型的声明。
Metal编译器负责根据数据类型的需要将数据项对齐到适当的对齐位置。对于声明为数据类型指针的图形或并行计算函数的参数,Metal编译器假设指针或引用的对象总是按照数据类型的要求进行适当对齐。