2019-09-04资源对象:缓冲区和纹理

本章介绍MTLResource用于存储未格式化内存和格式化图像数据的Metal资源对象。有两种类型的MTLResource对象:

  • MTLBuffer表示可以包含任何类型数据的未格式化内存的分配。缓冲区通常用于顶点,着色器和计算状态数据。
  • MTLTexture表示具有指定纹理类型和像素格式的格式化图像数据的分配。纹理对象用作顶点,片段或计算函数的源纹理,以及存储图形渲染输出(即作为附件)。

MTLSamplerState本章还讨论了这些对象。虽然采样器本身不是资源,但在使用纹理对象执行查找计算时会使用它们。

缓冲区是内存的无类型分配

MTLBuffer对象表示的存储器的分配,它可以包含任何类型的数据。

创建缓冲区对象

MTLDevice方法创建并返回一个MTLBuffer对象:

  • newBufferWithLength:options:方法MTLBuffer使用新的存储分配创建对象。

  • newBufferWithBytes:length:options:方法MTLBuffer通过将数据从现有存储(位于CPU地址pointer)复制到新的存储分配中来创建对象。

  • newBufferWithBytesNoCopy:length:options:deallocator:方法创建MTLBuffer具有现有存储分配的对象,并且不为此对象分配任何新存储。

所有缓冲区创建方法都有输入值length来指示存储分配的大小(以字节为单位)。所有方法也接受一个MTLResourceOptions对象options,可以修改创建的缓冲区的行为。如果值为options0,则默认值用于资源选项。

缓冲方法

该MTLBuffer协议有以下方法:

  • 该contents方法返回缓冲区存储分配的CPU地址。

  • 该newTextureWithDescriptor:offset:bytesPerRow:方法创建一种特殊的纹理对象,引用缓冲区的数据。创建纹理对象中详细介绍了此方法。

纹理是格式化图像数据

MTLTexture对象表示可被用作用于顶点着色器资源,片段着色器,或计算功能格式化的图像数据的分配,或者作为附件被用作渲染目的地。MTLTexture对象可以有一个以下结构:

  • 1D,2D或3D图像

  • 一维或一维2D图像

  • 一个立方体六个2D图像

MTLPixelFormat指定MTLTexture对象中单个像素的组织。像素格式在Pixel Formats for Textures中进一步讨论。

创建纹理对象

以下方法创建并返回一个MTLTexture对象:

  • 创建具有纹理图像数据的新存储分配的对象的newTextureWithDescriptor:方法,使用对象来描述纹理的属性。MTLDevice``MTLTextureMTLTextureDescriptor

  • newTextureViewWithPixelFormat:的方法MTLTexture创建一个MTLTexture共享相同的存储分配作为调用对象MTLTexture的对象。由于它们共享相同的存储空间,因此对新纹理对象的像素的任何更改都会反映在调用纹理对象中,反之亦然。对于新创建的纹理,该newTextureViewWithPixelFormat:方法重新解释调用MTLTexture对象的存储分配的现有纹理图像数据,就像数据以指定的像素格式存储一样。在MTLPixelFormat新的纹理对象必须是兼容MTLPixelFormat原始纹理的对象。(有关普通,压缩和压缩像素格式的详细信息,请参阅纹理的像素格式。)

  • 所述newTextureWithDescriptor:offset:bytesPerRow:的方法MTLBuffer创建一个MTLTexture共享主叫的存储分配对象MTLBuffer对象作为其纹理图像数据。由于它们共享相同的存储,因此对新纹理对象的像素的任何更改都会反映在调用纹理对象中,反之亦然。在纹理和缓冲区之间共享存储可以防止使用某些纹理优化,例如像素调整或平铺。

使用纹理描述符创建纹理对象

MTLTextureDescriptor定义用于创建MTLTexture对象的属性,包括其图像大小(宽度,高度和深度),像素格式,排列(数组或多维数据集类型)和mipmap数。这些MTLTextureDescriptor属性仅在创建MTLTexture对象期间使用。创建MTLTexture对象后,其MTLTextureDescriptor对象中的属性更改不再对该纹理产生任何影响。

要从描述符创建一个或多个纹理:

  1. 创建一个MTLTextureDescriptor包含描述纹理数据的纹理属性的自定义对象:

    • textureType属性指定纹理的维度和排列(例如,数组或多维数据集)。

    • width,height和depth属性在基级纹理的mipmap的每个维度指定像素大小。

    • 该pixelFormat属性指定像素在纹理中的存储方式。

    • arrayLength属性指定一个MTLTextureType1DArray或MTLTextureType2DArray类型纹理对象的数组元素的数量。

    • mipmapLevelCount属性指定mipmap级别的数量。

    • sampleCount属性指定每个像素中的样本数。

    • resourceOptions属性指定其内存分配的行为。

  2. MTLTextureDescriptor通过调用对象的newTextureWithDescriptor:方法从对象创建纹理MTLDevice。纹理创建后,调用replaceRegion:mipmapLevel:slice:withBytes:bytesPerRow:bytesPerImage:`方法来加载纹理图像数据,如将图像数据复制到纹理和从纹理复制图像数据中所述。

  3. 要创建更多MTLTexture对象,可以重用相同的MTLTextureDescriptor对象,根据需要修改描述符的属性值。

清单3-1显示了用于创建纹理描述符txDesc并为3D,64x64x64纹理设置其属性的代码。

MTLTextureDescriptor * txDesc = [[MTLTextureDescriptor alloc] init];
txDesc.textureType = MTLTextureType3D;
txDesc.height = 64;
txDesc.width = 64;
txDesc.depth = 64;
txDesc.pixelFormat = MTLPixelFormatBGRA8Unorm;
txDesc.arrayLength = 1;
txDesc.mipmapLevelCount = 1;
id  aTexture = [device newTextureWithDescriptor:txDesc];

使用纹理切片 没理解

slice是单个一维,二维或三维纹理图像和其所有相关的mipmap。对于每个切片:

  • 由指定的基级的mipmap的大小width,height和depth所述的属性MTLTextureDescriptor`的对象。

  • [我没看懂] mipmap级别i的缩放大小由max(1,floor(width/ 2 i))x max(1,floor(height/ 2 i))x max(1,floor(depth/ 2 i))指定。最大mipmap级别是第一个mipmap级别,其中实现了1 x 1 x 1的大小。

  • [我没看懂] 在一个切片的mipmap级的数目可以按楼层来确定(日志2(MAX( ,widthheight)))+depth 1。

所有纹理对象至少有一个切片; 立方体和数组纹理类型可能有多个切片。在写入和读取在将图像数据复制到纹理和从纹理复制中讨论的纹理图像数据的方法中,slice是基于零的输入值。对于1D,2D或3D纹理,只有一个切片,因此值slice必须为0.立方体纹理具有6个总2D切片,从0到5寻址。对于1DArray和2DArray纹理类型,每个数组元素代表一片。例如,对于arrayLength= 10 的2DArray纹理类型,总共有10个切片,从0到9寻址。要从整体纹理结构中选择单个1D,2D或3D图像,首先选择切片,然后选择该切片中的mipmap级别。

使用便捷方法创建纹理描述符

对于常见的2D和立方体纹理,请使用以下便捷方法创建一个MTLTextureDescriptor自动设置其若干属性值的对象:

  • texture2DDescriptorWithPixelFormat:width:height:mipmapped:方法MTLTextureDescriptor为2D纹理创建对象。的widthheight值定义了2D纹理的尺寸。该type属性被自动设置为MTLTextureType2D,并且deptharrayLength被设置为1。

  • textureCubeDescriptorWithPixelFormat:size:mipmapped:方法创建一个MTLTextureDescriptor用于立方织构,其中所述对象type属性设置为MTLTextureTypeCubewidthheight被设置为大小,depth并且arrayLength`被设置为1。

两种MTLTextureDescriptor便捷方法都接受输入值,该输入值pixelFormat定义纹理的像素格式。两种方法也接受输入值mipmapped,该值确定纹理图像是否是mipmapped。(如果mipmappedYES,纹理是mipmapped。)

清单3-2使用该texture2DDescriptorWithPixelFormat:width:height:mipmapped:方法64x64为未经mipmap 的2D纹理创建描述符对象。

清单3-2 使用方便的纹理描述符创建纹理对象

MTLTextureDescriptor * texDesc = [MTLTextureDescriptor 
         texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm 
         width:64 height:64 mipmapped:NO];
id  myTexture = [device newTextureWithDescriptor:texDesc];

将图像数据复制到纹理和从纹理复制

要将图像数据同步复制到MTLTexture对象的存储分配中或从中复制数据,请使用以下方法:

  • replaceRegion:mipmapLevel:slice:withBytes:bytesPerRow:bytesPerImage:将来自调用者指针的像素数据区域复制到指定纹理切片的存储分配的一部分中。replaceRegion:mipmapLevel:withBytes:bytesPerRow:是一种类似的便捷方法,它将像素数据区域复制到默认切片中,假设切片相关参数的默认值(即slice= 0和bytesPerImage= 0)。

  • getBytes:bytesPerRow:bytesPerImage:fromRegion:mipmapLevel:slice:从指定的纹理切片检索像素数据的区域。getBytes:bytesPerRow:fromRegion:mipmapLevel:是一种类似的便捷方法,它从默认切片中检索像素数据的区域,假设切片相关参数的默认值(slice= 0和bytesPerImage= 0)。

清单3-3显示了如何调用replaceRegion:mipmapLevel:slice:withBytes:bytesPerRow:bytesPerImage:以从textureData切片0和mipmap级别的系统内存中的源数据指定纹理图像0

清单3-3 将图像数据复制到纹理中

// pixelSize是一个像素的大小,以字节为单位
// width,height  - 每个维度中的像素数
NSUInteger myRowBytes = width * pixelSize;
NSUInteger myImageBytes = rowBytes * height;
[tex replaceRegion:MTLRegionMake2D(0,0,width,height)
    mipmapLevel:0 slice:0 withBytes:textureData
    bytesPerRow:myRowBytes bytesPerImage:myImageBytes];

纹理的像素格式

MTLPixelFormat指定MTLTexture对象的各个像素中的颜色,深度和模板数据存储的组织。有三种像素格式:普通,打包和压缩。

  • 普通格式只有常规的8位,16位或32位颜色分量。每个组件都安排在增加的内存地址中,第一个列出的组件位于最低地址。例如,MTLPixelFormatRGBA8Unorm是32位格式,每个颜色分量有8位; 最低地址包含红色,下一个地址包含绿色,依此类推。相反,对于MTLPixelFormatBGRA8Unorm,最低地址包含蓝色,下一个地址包含绿色,依此类推。

  • 打包格式将多个组件组合成一个16位或32位值,其中组件从最低位到最高位(LSB到MSB)存储。例如,MTLPixelFormatRGB10A2Uint是一个32位打包格式,由三个10位通道(对于R,G和B)和两个用于alpha的位组成。

  • 压缩格式以像素块排列,并且每个块的布局特定于该像素格式。压缩像素格式只能用于2D,2D阵列或立方体纹理类型。压缩格式不能用于创建1D,2DMultisample或3D纹理。

MTLPixelFormatGBGR422和MTLPixelFormatBGRG422是被用于存储像素的YUV色彩空间特殊的像素格式。这些格式仅支持2D纹理(但不包括2D数组,也不支持立方体类型),没有mipmap和偶数width

多种像素格式存储具有sRGB颜色空间值的颜色分量(例如,MTLPixelFormatRGBA8Unorm_sRGB或MTLPixelFormatETC2_RGB8_sRGB)。当采样操作引用具有sRGB像素格式的纹理时,Metal实现会在采样操作发生之前将sRGB颜色空间组件转换为线性颜色空间。从sRGB组件S到线性组件L的转换如下:

  • 如果S <= 0.04045,则L = S / 12.92

  • 如果S> 0.04045,则L =((S + 0.055)/1.055) 2.4

相反,当渲染为使用具有sRGB像素格式的纹理的颜色可渲染附件时,实现将线性颜色值转换为sRGB,如下所示:

  • 如果L <= 0.0031308,则S = L * 12.92

  • 如果L> 0.0031308,则S =(1.055 * L 0.41667) - 0.055

有关用于渲染的像素格式的更多信息,请参阅创建渲染通道描述符。

为纹理查找创建采样器状态对象

MTLSamplerState对象定义用于当一个图形或计算功能的上执行纹理采样操作的寻址,滤波,和其它性质MTLTexture的对象。采样器描述符定义采样器状态对象的属性。要创建采样器状态对象:

  1. 调用对象的newSamplerStateWithDescriptor:方法MTLDevice来创建MTLSamplerDescriptor对象。

  2. MTLSamplerDescriptor对象中设置所需的值,包括过滤选项,寻址模式,最大各向异性和细节级别参数。

  3. MTLSamplerState通过调用创建描述符newSamplerStateWithDescriptor:的MTLDevice对象的方法,从sampler描述符创建一个对象。

您可以重用sampler描述符对象来创建更多MTLSamplerState对象,根据需要修改描述符的属性值。描述符的属性仅在对象创建期间使用。创建采样器状态后,更改其描述符中的属性不再对该采样器状态产生影响。

清单3-4是一个代码示例,它创建MTLSamplerDescriptor并配置它以创建一个MTLSamplerState。为描述符对象的过滤器和地址模式属性设置非默认值。然后,该newSamplerStateWithDescriptor:方法使用sampler描述符来创建采样器状态对象。
清单3-4 创建一个采样器状态对象

//创建MTLSamplerDescriptor
MTLSamplerDescriptor * desc = [[MTLSamplerDescriptor alloc] init];
desc.minFilter = MTLSamplerMinMagFilterLinear;
desc.minFilter = MTLSamplerMinMagFilterLinear;
desc.minFilter = MTLSamplerMinMagFilterLinear;
desc.tAddressMode = MTLSamplerAddressModeRepeat;
//以下所有属性都有默认值
desc.mipFilter = MTLSamplerMipFilterNotMipmapped;
desc.maxAnisotropy = 1U;
desc.normalizedCoords = YES;
desc.lodMinClamp = 0.0f;
desc.lodMaxClamp = FLT_MAX;
//创建MTLSamplerState
id  sampler = [device newSamplerStateWithDescriptor:desc];

保持CPU和GPU内存之间的一致性

CPU和GPU都可以访问MTLResource对象的底层存储。但是,GPU与主机CPU异步操作,因此在使用主机CPU访问这些资源的存储时请记住以下几点。

执行MTLCommandBuffer对象时,MTLDevice只有当(并且仅当)主机CPU在提交对象之前进行了这些更改时,才能保证对象仅观察主机CPU对该MTLResource对象引用的任何对象的存储分配所做的任何更改。也就是说,对象可能不会观察到在提交相应对象之后主机CPU所做的资源的更改(即,对象的属性是)。MTLCommandBuffer MTLCommandBuffer MTLDevice MTLCommandBuffer
status MTLCommandBuffer MTLCommandBufferStatusCommitted

类似地,后MTLDevice对象执行MTLCommandBuffer对象,主机CPU只保证遵守任何更改MTLDevice对象使得由该命令缓冲区中引用的任何资源的存储分配,如果命令缓冲区完成执行(即,status所述的属性MTLCommandBuffer对象是MTLCommandBufferStatusCompleted)。

你可能感兴趣的:(2019-09-04资源对象:缓冲区和纹理)