版本记录
版本号 | 时间 |
---|---|
V1.0 | 2018.11.04 星期日 |
前言
很多做视频和图像的,相信对这个框架都不是很陌生,它渲染高级3D图形,并使用GPU执行数据并行计算。接下来的几篇我们就详细的解析这个框架。感兴趣的看下面几篇文章。
1. Metal框架详细解析(一)—— 基本概览
2. Metal框架详细解析(二) —— 器件和命令(一)
3. Metal框架详细解析(三) —— 渲染简单的2D三角形(一)
4. Metal框架详细解析(四) —— 关于GPU Family 4(一)
5. Metal框架详细解析(五) —— 关于GPU Family 4之关于Imageblocks(二)
6. Metal框架详细解析(六) —— 关于GPU Family 4之关于Tile Shading(三)
7. Metal框架详细解析(七) —— 关于GPU Family 4之关于光栅顺序组(四)
8. Metal框架详细解析(八) —— 关于GPU Family 4之关于增强的MSAA和Imageblock采样覆盖控制(五)
9. Metal框架详细解析(九) —— 关于GPU Family 4之关于线程组共享(六)
10. Metal框架详细解析(十) —— 基本组件(一)
11. Metal框架详细解析(十一) —— 基本组件之器件选择 - 图形渲染的器件选择(二)
12. Metal框架详细解析(十二) —— 基本组件之器件选择 - 计算处理的设备选择(三)
13. Metal框架详细解析(十三) —— 计算处理(一)
14. Metal框架详细解析(十四) —— 计算处理之你好,计算(二)
15. Metal框架详细解析(十五) —— 计算处理之关于线程和线程组(三)
16. Metal框架详细解析(十六) —— 计算处理之计算线程组和网格大小(四)
17. Metal框架详细解析(十七) —— 工具、分析和调试(一)
18. Metal框架详细解析(十八) —— 工具、分析和调试之Metal GPU Capture(二)
19. Metal框架详细解析(十九) —— 工具、分析和调试之GPU活动监视器(三)
20. Metal框架详细解析(二十) —— 工具、分析和调试之关于Metal着色语言文件名扩展名、使用Metal的命令行工具构建库和标记Metal对象和命令(四)
21. Metal框架详细解析(二十一) —— 基本课程之基本缓冲区(一)
22. Metal框架详细解析(二十二) —— 基本课程之基本纹理(二)
23. Metal框架详细解析(二十三) —— 基本课程之CPU和GPU同步(三)
24. Metal框架详细解析(二十四) —— 基本课程之参数缓冲 - 基本参数缓冲(四)
25. Metal框架详细解析(二十五) —— 基本课程之参数缓冲 - 带有数组和资源堆的参数缓冲区(五)
26. Metal框架详细解析(二十六) —— 基本课程之参数缓冲 - 具有GPU编码的参数缓冲区(六)
27. Metal框架详细解析(二十七) —— 高级技术之图层选择的反射(一)
28. Metal框架详细解析(二十八) —— 高级技术之使用专用函数的LOD(一)
29. Metal框架详细解析(二十九) —— 高级技术之具有参数缓冲区的动态地形(一)
30. Metal框架详细解析(三十) —— 延迟照明(一)
31. Metal框架详细解析(三十一) —— 在视图中混合Metal和OpenGL渲染(一)
32. Metal框架详细解析(三十二) —— Metal渲染管道教程(一)
33. Metal框架详细解析(三十三) —— Metal渲染管道教程(二)
34. Metal框架详细解析(三十四) —— Hello Metal! 一个简单的三角形的实现(一)
35. Metal框架详细解析(三十五) —— Hello Metal! 一个简单的三角形的实现(二)
36. Metal框架详细解析(三十六) —— Metal编程指南之概览(一)
37. Metal框架详细解析(三十七) —— Metal编程指南之基本Metal概念(二)
38. Metal框架详细解析(三十八) —— Metal编程指南之命令组织和执行模型(三)
Resource Objects: Buffers and Textures - 资源对象:缓冲区和纹理
本章介绍用于存储未格式化内存和格式化图像数据的Metal资源对象(MTLResource)。 有两种类型的MTLResource
对象:
- MTLBuffer表示可以包含任何类型数据的未格式化内存的分配。 缓冲区通常用于顶点,着色器和计算状态数据。
-
MTLTexture表示具有指定纹理类型和像素格式的格式化图像数据的分配。 纹理对象用作顶点,片段或计算函数的源纹理,以及存储图形渲染输出(即作为
attachment
)。
本章还讨论了MTLSamplerState对象。 虽然采样器本身不是资源,但在使用纹理对象执行查找计算时会使用它们。
Buffers Are Typeless Allocations of Memory - 缓冲区是内存的无类型分配
MTLBuffer对象表示可以包含任何类型数据的内存分配。
1. Creating a Buffer Object - 创建缓冲区对象
以下MTLDevice方法创建并返回MTLBuffer对象:
-
newBufferWithLength:options:方法创建具有新存储分配的
MTLBuffer
对象。 -
newBufferWithBytes:length:options:方法通过将数据从现有存储(位于CPU地址指针)复制到新的存储分配中来创建
MTLBuffer
对象。 -
newBufferWithBytesNoCopy:length:options:deallocator:方法创建具有现有存储分配的
MTLBuffer
对象,并且不为此对象分配任何新存储。
所有缓冲区创建方法都具有输入值length
,以指示存储分配的大小(以字节为单位)。所有方法还接受MTLResourceOptions
对象,以获取可以修改创建的缓冲区行为的options
。如果options
的值为0,则默认值用于资源选项。
2. Buffer Methods - 缓冲方法
MTLBuffer协议具有以下方法:
- contents方法返回缓冲区存储分配的CPU地址。
- newTextureWithDescriptor:offset:bytesPerRow:方法创建一种特殊的纹理对象,引用缓冲区的数据。 Creating a Texture Object中详细介绍了此方法。
Textures Are Formatted Image Data - 纹理是格式化图像数据
MTLTexture对象表示格式化图像数据的分配,可以将其用作顶点着色器,片段着色器或计算函数的资源,或者用作要用作渲染目标的attachment
。 MTLTexture
对象可以具有以下结构之一:
- 1D,2D或3D图像
- 一维或一维2D图像
- 六个2D图像的立方体
MTLPixelFormat
指定MTLTexture
对象中各个像素的组织。像素格式在Pixel Formats for Textures中进一步讨论。
1. Creating a Texture Object - 创建纹理对象
以下方法创建并返回MTLTexture对象:
-
newTextureWithDescriptor:方法使用MTLTextureDescriptor对象创建一个具有纹理图像数据的新存储分配的
MTLTexture
对象来描述纹理的属性。 -
MTLTexture
的newTextureViewWithPixelFormat:方法创建一个MTLTexture
对象,该对象与调用MTLTexture对象共享相同的存储分配。由于它们共享相同的存储空间,因此对新纹理对象的像素的任何更改都会反映在调用纹理对象中,反之亦然。对于新创建的纹理,newTextureViewWithPixelFormat:方法重新解释调用MTLTexture
对象的存储分配的现有纹理图像数据,就好像数据以指定的像素格式存储一样。新纹理对象的MTLPixelFormat
必须与原始纹理对象的MTLPixelFormat
兼容。 (有关普通,压缩和压缩像素格式的详细信息,请参阅Pixel Formats for Textures。) -
MTLBuffer
的newTextureWithDescriptor:offset:bytesPerRow:方法创建一个MTLTexture
对象,该对象共享调用MTLBuffer对象的存储分配作为其纹理图像数据。由于它们共享相同的存储,因此对新纹理对象的像素的任何更改都会反映在调用纹理对象中,反之亦然。在纹理和缓冲区之间共享存储可以防止使用某些纹理优化,例如像素调整或平铺。
2. Creating a Texture Object with a Texture Descriptor - 使用纹理描述符创建纹理对象
MTLTextureDescriptor定义用于创建MTLTexture对象的属性,包括其图像大小(宽度,高度和深度),像素格式,排列(数组或多维数据集类型)和mipmap
数。 MTLTextureDescriptor
属性仅在创建MTLTexture
对象期间使用。创建MTLTexture
对象后,其MTLTextureDescriptor
对象中的属性更改不再对该纹理产生任何影响。
要从描述符创建一个或多个纹理:
-
1) 创建一个自定义MTLTextureDescriptor对象,其中包含描述纹理数据的纹理属性:
- textureType属性指定纹理的维度和排列(例如,数组或多维数据集)。
-
width, height和depth属性指定基级纹理
mipmap
的每个维度中的像素大小。 - pixelFormat属性指定像素在纹理中的存储方式。
- arrayLength属性指定MTLTextureType1DArray或MTLTextureType2DArray类型纹理对象的数组元素数。
-
mipmapLevelCount属性指定
mipmap
级别的数量。 - sampleCount属性指定每个像素中的样本数。
- resourceOptions属性指定其内存分配的行为。
2) 通过调用
MTLDevice
对象的newTextureWithDescriptor:方法从MTLTextureDescriptor
对象创建纹理。在纹理创建之后,调用replaceRegion:mipmapLevel:slice:withBytes:bytesPerRow:bytesPerImage:加载纹理图像数据的方法,详见Copying Image Data to and from a Texture。3) 要创建更多
MTLTexture
对象,可以重用相同的MTLTextureDescriptor
对象,根据需要修改描述符的属性值。
Listing 3-1
显示了用于创建纹理描述符txDesc
并为3D
,64x64x64
纹理设置其属性的代码。
// Listing 3-1 Creating a Texture Object with a Custom Texture Descriptor
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];
3. Working with Texture Slices - 使用纹理切片
切片(slice)
是单个1D,2D或3D纹理图像及其所有关联的mipmap
。对于每个切片:
- 基准级别
mipmap
的大小由MTLTextureDescriptor
对象的width
,height
和depth
属性指定。 -
mipmap
级别i
的缩放尺寸由max(1,floor(width / 2i))x max(1,floor(height / 2i))x max(1,floor(depth / 2i))
指定。最大mipmap
级别是第一个mipmap
级别,其中实现了1 x 1 x 1
的大小。 - 一个切片中的
mipmap
级别的数量可以由floor(log2(max(width,height,depth)))+ 1
确定。
所有纹理对象至少有一个切片;立方体和数组纹理类型可能有多个切片。在写入和读取在纹理中复制图像数据和Copying Image Data to and from a Texture中讨论的纹理图像数据的方法中,slice
是从零开始的输入值。对于1D,2D或3D纹理,只有一个切片,因此切片的值必须为0。立方体纹理具有6个总2D切片,从0到5寻址。对于1DArray
和2DArray
纹理类型,每个数组element
代表一个切片。例如,对于arrayLength = 10
的2DArray
纹理类型,总共有10个切片,从0到9寻址。要从整体纹理结构中选择单个1D,2D或3D图像,首先选择切片,然后选择该切片中的mipmap
级别。
4. Creating a Texture Descriptor with Convenience Methods - 使用便捷方法创建纹理描述符
对于常见的2D和立方体纹理,请使用以下便捷方法创建MTLTextureDescriptor
对象,并自动设置其若干属性值:
-
texture2DDescriptorWithPixelFormat:width:height:mipmapped:方法为2D纹理创建
MTLTextureDescriptor
对象。width
和height
值定义2D纹理的尺寸。type
属性自动设置为MTLTextureType2D
,depth
和arrayLength
设置为1。 -
textureCubeDescriptorWithPixelFormat:size:mipmapped:方法为立方体纹理创建
MTLTextureDescriptor
对象,其中type
属性设置为MTLTextureTypeCube
,width
和height
设置为size
,depth
和arrayLength
设置为1。
两种MTLTextureDescriptor
便捷方法都接受输入值pixelFormat
,它定义纹理的像素格式。两种方法也接受mipmapped
的输入值,该值确定纹理图像是否是mipmapped
。 (如果mipmapped
为YES,则纹理被mipmap
处理。)
Listing 3-2
使用texture2DDescriptorWithPixelFormat:width:height:mipmapped:
方法为未mipmapped
的64x64 2D
纹理创建描述符对象。
Listing 3-2 Creating a Texture Object with a Convenience Texture Descriptor
MTLTextureDescriptor *texDesc = [MTLTextureDescriptor
texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
width:64 height:64 mipmapped:NO];
id <MTLTexture> myTexture = [device newTextureWithDescriptor:texDesc];
5. Copying Image Data to and from a Texture - 将图像数据复制到纹理和从纹理复制
要将图像数据同步复制到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
)。
Listing 3-3
显示了如何调用replaceRegion:mipmapLevel:slice:withBytes:bytesPerRow:bytesPerImage:从系统内存中的源数据指定纹理图像,textureData
,在切片0
和mipmap
级别0。
// Listing 3-3 Copying Image Data into the Texture
// pixelSize is the size of one pixel, in bytes
// width, height - number of pixels in each dimension
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];
6. Pixel Formats for Textures - 纹理的像素格式
MTLPixelFormat
指定MTLTexture
对象的各个像素中的颜色,深度和模板数据存储的组织。有三种像素格式:ordinary, packed, and compressed
。
-
Ordinary
格式只有常规的8位,16位或32位颜色分量。每个组件都安排在增加的内存地址中,第一个列出的组件位于最低地址。例如,MTLPixelFormatRGBA8Unorm是32位格式,每个颜色分量有8位;最低地址包含红色,下一个地址包含绿色,依此类推。相反,对于MTLPixelFormatBGRA8Unorm,最低地址包含蓝色,下一个地址包含绿色,依此类推。 -
Packed
格式将多个组件组合成一个16位或32位值,其中组件从最低位到最高位(LSB到MSB)存储。例如,MTLPixelFormatRGB10A2Uint是一种32位打包格式,由三个10位通道(R,G和B)和两位alpha
组成。 -
Compressed
格式以像素块排列,每个块的布局特定于该像素格式。压缩像素格式只能用于2D,2D阵列或立方体纹理类型。压缩格式不能用于创建1D
,2DMultisample
或3D
纹理。
MTLPixelFormatGBGR422和MTLPixelFormatBGRG422是特殊的像素格式,用于存储YUV
颜色空间中的像素。这些格式仅支持2D纹理(但不包括2D数组,也不支持立方体类型),没有mipmaps
和均匀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 * L0.41667) - 0.055
有关用于渲染的像素格式的更多信息,请参阅Creating a Render Pass Descriptor。
Creating a Sampler States Object for Texture Lookup - 为纹理查找创建采样器状态对象
MTLSamplerState对象定义在图形或计算函数对MTLTexture
对象执行纹理采样操作时使用的寻址,过滤和其他属性。采样器描述符定义采样器状态对象的属性。要创建采样器状态对象:
- 调用MTLDevice对象的newSamplerStateWithDescriptor:方法以创建MTLSamplerDescriptor对象。
- 在
MTLSamplerDescriptor
对象中设置所需的值,包括过滤选项,寻址模式,最大各向异性和细节级别参数。 - 通过调用创建描述符的
MTLDevice
对象的newSamplerStateWithDescriptor:方法,从采样器描述符创建MTLSamplerState对象。
您可以重用sampler
描述符对象来创建更多MTLSamplerState
对象,根据需要修改描述符的属性值。描述符的属性仅在对象创建期间使用。创建采样器状态后,更改其描述符中的属性不再对该采样器状态产生影响。
Listing 3-4
是一个代码示例,它创建MTLSamplerDescriptor
并对其进行配置以创建MTLSamplerState。为描述符对象的过滤器和地址模式属性设置非默认值。然后newSamplerStateWithDescriptor:方法使用sampler
描述符来创建一个采样器状态对象
Listing 3-4 Creating a Sampler State Object
// create MTLSamplerDescriptor
MTLSamplerDescriptor *desc = [[MTLSamplerDescriptor alloc] init];
desc.minFilter = MTLSamplerMinMagFilterLinear;
desc.magFilter = MTLSamplerMinMagFilterLinear;
desc.sAddressMode = MTLSamplerAddressModeRepeat;
desc.tAddressMode = MTLSamplerAddressModeRepeat;
// all properties below have default values
desc.mipFilter = MTLSamplerMipFilterNotMipmapped;
desc.maxAnisotropy = 1U;
desc.normalizedCoords = YES;
desc.lodMinClamp = 0.0f;
desc.lodMaxClamp = FLT_MAX;
// create MTLSamplerState
id <MTLSamplerState> sampler = [device newSamplerStateWithDescriptor:desc];
Maintaining Coherency Between CPU and GPU Memory - 保持CPU和GPU内存之间的一致性
CPU和GPU都可以访问MTLResource对象的底层存储。但是,GPU与主机CPU异步操作,因此在使用主机CPU访问这些资源的存储时请记住以下几点。
执行MTLCommandBuffer对象时,MTLDevice对象仅保证观察主机CPU对该MTLCommandBuffer
对象引用的任何MTLResource
对象的存储分配所做的任何更改,如果(并且仅当)主机CPU在MTLCommandBuffer
对象已提交之前进行了这些更改。也就是说,MTLDevice
对象可能不会观察到在提交相应的MTLCommandBuffer
对象之后主机CPU所做的资源的更改(即,MTLCommandBuffer
对象的status属性是MTLCommandBufferStatusCommitted)。
类似地,在MTLDevice
对象执行MTLCommandBuffer
对象之后,如果命令缓冲区已完成执行(即MTLCommandBuffer
对象的status
属性是MTLCommandBufferStatusCompleted),则主机CPU仅保证观察MTLDevice对象对该命令缓冲区引用的任何资源的存储分配所做的任何更改 )。
后记
本篇主要讲述了Metal编程指南之资源对象:缓冲区和纹理,感兴趣的给个赞或者关注~~~