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

2019-09-28  本文已影响0人  胡志强

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

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

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

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

创建缓冲区对象

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

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

缓冲方法

MTLBuffer协议有以下方法:

纹理是格式化图像数据

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

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

创建纹理对象

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

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

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

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

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

  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 <MTLTexture> aTexture = [device newTextureWithDescriptor:txDesc];

使用纹理切片 没理解

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

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

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

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

两种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 <MTLTexture> myTexture = [device newTextureWithDescriptor:texDesc];

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

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

清单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对象的各个像素中的颜色,深度和模板数据存储的组织。有三种像素格式:普通,打包和压缩。

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

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

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

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

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

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 <MTLSamplerState> 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)。

上一篇 下一篇

猜你喜欢

热点阅读