原子数据类型 - Atomic Data Type
Metal原子数据类型被限制于只能在Metal着色语言供的原子函数中使用。原子函数是一组C++ 14标准的原子同步函数。Metal原子函数必须操作Metal原子数据类型数据。
Metal支持的原子类型:
atomic_int - All OS: since Metal 1.0
atomic_uint - All OS: since Metal 1.0
atomic_bool - iOS: since Metal 2.0; not supported on macOS
atomic<t style="box-sizing: border-box;"> - iOS: since Metal 2.0; not supported on macOS
atomic<t style="box-sizing: border-box;"> - represents templated types, where T can be int, uint, or bool.</t></t>
原子操作(atomic operation)指的是由多步操作组成的一个操作。如果该操作不能原子地执行,则要么执行完所有步骤,要么一步也不执行,不可能只执行所有步骤的一个子集。
任何要求多于一个函数调用的操作都不是原子操作,因为在两个函数调用之间,内核可能会临时挂起线程,执行其他的操作,当内核切换回当前线程时,之前的数据可能别修改,所以不能保证是原子操作。
在程序中使用这些数据类型的时候,编译器将保证针对原子数据类型的操作都是原子性的。也就是说,编译器保证多个线程访问这个共享资源的正确性。这样,我们在程序中就可以较少锁的使用,提高程序效率。
像素数据类型 - Pixel Data Types
所有操作系统:自Metal 2.0以来支持的像素数据类型。
Metal像素数据类型是一个模板类型,描述像素格式类型及其对应的ALU类型。ALU类型表示加载操作返回的类型和为存储操作指定的输入类型。像素数据类型通常在所有地址空间中可用。(有关地址空间的更多信息,请参见第4节。)
表2.6列出了金属着色语言中支持的像素数据类型,以及它们的大小和对齐方式。
下表为Metal像素数据类型:
只允许像素数据类型及其对应的ALU类型之间的赋值和相等/不等比较。
示例:
示例:
缓存 - Buffers
Metal中实现的缓存是一个指针,它指向一个在device或是constant地址空间中的内建或是用户自定义的数据块。缓 存可以被定义在程序域中,或是当做函数的参数传递。
普通的Metal Buffers包含:
- 基本类型,如float和int
- 向量和矩阵类型
- 缓冲区类型数组
- 缓冲类型的结构
- 缓冲类型的联合
下面展示的函数参数中的展示的缓冲区参数
其中前两个参数为设备地址空间的缓存(device address space),第三个buffer在常量地址空间(constant address space)
纹理 - Textures
纹理数据类型是一个句柄,它指向一个1维、2维或是3维纹理数据,而纹理数据对应着一个纹理的某个level的mipmap 的全部或是一部分。
下面的模板定义了特定的纹理数据类型:
带有深度格式的纹理必须被声明为下面纹理数据类型中的一个:
macOS从Metal 2.0开始支持texture2d_ms_array和depth2d_ms_array。自Metal 1.0以来支持的所有其他类型。
iOS从Metal 1.0开始支持除texture2d_ms_array和depth2d_ms_array之外的所有类型。
T设定了从纹理中读取或是向纹理中写入时的颜色类型,纹理数据类型(除了深度纹理类型),T可以是half,float, short,ushort, int 或是uint。对于深度纹理,T必须是float。
注意:如果T是int或是short,纹理相关的数据必须使用有符号整形。如果T是uint或是ushort,纹理相关数据必须使用 无符号整形。如果T是half,和纹理相关数据必须要么是归一化的(整形),要么是half,要么是单精度浮点数。
access修饰符描述了纹理如何被访问。
被支持的access修饰符如下:
- sample(supported Metal1.0) 纹理对象可以被采样,采样意味着使用或是不使用采样器从纹理中读取数据
- read (supported Metal1.0) - 不使用采样器,一个图形渲染函数或是一个并行计算函数可以读取纹理对象
- write(supported Metal1.0) - 一个图形渲染函数或是一个并行计算函数可以向纹理对象写入数据
- read_write(supported Metal1.2) - 一个图形渲染函数或是一个并行计算函数可以向纹理对象写入数据和写入数据
对于多重采样纹理,只有read修饰符是支持的。对于深度纹理,只有sample和read修饰符是支持的。纹理指针或是引用是不支持的,将会导致编译错误。
下面的例子,纹理对象参数使用了access修饰符
您可以使用纹理类型作为函数中声明的任何变量的变量类型。函数中声明的纹理类型变量的access属性必须是access::read或access:sample。
示例:
纹理缓冲区 - Texture Buffers
所有系统: Texture buffers supported since Metal 2.1.
纹理缓冲区是一种纹理类型,它可以访问一个大的一维像素数据数组,并在该数据上执行像素格式之间的动态类型转换,具有优化的性能。纹理缓冲区比其他技术更有效地处理类型转换,允许访问更大的元素计数,并处理越界读取访问。类似的类型转换可以在没有纹理缓冲区的情况下实现,方法有:
- 从纹理对象读取像素数据(就像其他数组一样),并将像素转换为所需的格式。
- 在缓冲区对象的数据周围包装一个纹理对象,然后通过纹理访问共享的缓冲区数据。这种包装技术提供了像素转换,但需要额外的处理步骤,而且纹理的大小是有限的。
下面的模板定义了texture_buffer类型,您可以像使用任何纹理一样使用它:
texture_buffer
access可以是read 、write或read_write之一。
T指定从纹理缓冲区读取时返回组件的类型,或写入纹理缓冲区时指定的组件类型。对于纹理缓冲区,T可以是half、float、short、ushort、int或uint之一。
对于没有alpha通道的格式(如R、RG或RGB),越界读取返回(0,0,0,1)。对于带有alpha通道的格式(如RGBA),越界读取返回(0,0,0,0)。对于某些设备,越界读取可能会导致性能损失。
越界写入将被忽略。
纹理缓冲区可以支持比一般一维纹理(最大宽度为16384)更多的纹理数据。但是,您不能对纹理缓冲区进行采样。
纹理缓冲区还转换数据,以请求的纹理格式交付数据,而不管源文件的格式如何。创建纹理缓冲区时,可以指定缓冲区中数据的格式(例如,RGBA8Unorm),然后着色器函数可以将其读取为
转换类型(如float4)。因此,单个管道状态对象可以访问以不同像素格式存储的数据,而无需重新编译。
纹理缓冲区与纹理类型类似,可以声明为着色器函数的局部变量的类型。
采样器 - Samplers
在Metal着色语言中,采样器类型决定了如何对一个纹理进行采样操作。Metal框架代码中可以创建一个对应着色语言中的采样器的对象MTLSamplerState,这个对象作为图形渲染着色函数参数或是并行计算着色函数的参数传递。除了 在Metal框架代码中定义描述,一个采样器对象也可以在Metal着色语言程序中定义描述。如果是这种情况,那么只允许设定部分的采样器状态:寻址模式,过滤模式,归一化坐标,比较函数。
下表描述了Metal支持的采样器状态和关联数值(默认值)。在Metal着色语言程序中,这些状态可以在一个采样器 初始化时设定。
macOS:从Metal 1.2开始支持clamp_to_border地址模式和border_color。
iOS:不支持clamp_to_border地址模式或border_color。
使用clamp_to_border,纹理外部的采样只使用纹理坐标的边框颜色(不使用纹理边缘的任何颜色)。如果地址模式为clamp_to_border,则border_color是有效的。
clamp_to_zero等价于clamp_to_border,其边框颜色为transparent t_black(0.0, 0.0, 0.0),带有纹理中的alpha组件值。如果clamp_to_zero是一个或多个纹理坐标的地址模式,那么如果边框颜色为transparent t_black,其他纹理坐标可以使用clamp_to_border的地址模式。否则,行为是未定义的。
如果coord被设置为pixel, min_filter和mag_filter值必须相同,mip_filter值必须为none,地址模式必须为clamp_to_zero、clamp_to_border或clamp_to_edge。
除了枚举类型外,还可以指定采样器的最大各向异性滤波和LOD(详细级别)范围:
max_anisotropy(int value)
lod_clamp(float min, float max)
注意,在程序源代码中声明的采样器或常量缓冲区不需要这些属性限定符。必须使用constexpr声明在Metal着色语言源中初始化的采样器。