《Metal》官方文档005 --资源对象:缓冲区和纹理

资源对象:缓冲区和纹理

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

  • MTLBuffer表示可以包含任何类型数据的未格式化内存的分配。
    缓冲区通常用于顶点,着色器和计算状态数据。

  • MTLTexture表示具有指定纹理类型和像素格式的格式化图像数据的分配。纹理对象用作顶点,片段或计算函数的源纹理,以及存储图形渲染输出(即附件)。

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

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

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

创建缓冲区对象

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

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

缓冲方法

MTLBuffer协议具有以下的方法:

纹理是格式化的图像数据

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

  • 1D,2D或3D图像

  • 一维或二维图像阵列

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

MTLPixelFormat指定MTLTexture对象中各个像素的组织。像素格式在“ 像素格式”进一步讨论。

创建一个纹理对象

以下方法创建并返回一个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包含描述纹理数据的纹理属性的自定义对象:

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

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

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

清单3-1 使用自定义纹理描述符创建纹理对象

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。对于每个切片:

  • 由指定的基级的mipmap的大小widthheightdepth所述的属性MTLTextureDescriptor的对象。

  • mipmap级别i的缩放大小由max(1,floor(width/ 2 i))x max(1,floor(height/ 2 i))x max(1,floor(depth/ 2 i))指定。最大mipmap级别是第一个实现大小为1 x 1 x 1的mipmap级别。

  • 在一个切片的mipmap级的数目可以按楼层来确定(日志2(MAX( ,width,height)))+depth 1。

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

用方便的方法创建纹理描述符

对于常见的2D和多维数据集纹理,请使用以下便利方法创建一个MTLTextureDescriptor对象,其中的几个属性值自动设置:

两种MTLTextureDescriptor方便的方法都接受一个输入值,pixelFormat它定义了纹理的像素格式。两种方法也接受输入值mipmapped,该值决定纹理图像是否被映射。(如果mipmapped是YES,纹理是mipmap。)

清单3-2使用该texture2DDescriptorWithPixelFormat:width:height:mipmapped:方法64x64为未映射的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中的slice 0和mipmap级别的源数据中调用指定纹理图像0。

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

// 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];

纹理的像素格式

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纹理。

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

几个像素格式存储具有sRGB颜色空间值的颜色组件(例如,MTLPixelFormatRGBA8Unorm_sRGBMTLPixelFormatETC2_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对象的方法,从采样器描述符创建一个对象。

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

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

清单3-4 创建采样器状态对象

//创建MTLSamplerDescriptor

MTLSamplerDescriptor * desc = [[MTLSamplerDescriptor alloc] init];

desc.minFilter = MTLSamplerMinMagFilterLinear;

desc.magFilter = MTLSamplerMinMagFilterLinear;

desc.sAddressMode = MTLSamplerAddressModeRepeat;

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由该MTLCommandBuffer对象引用的任何对象的存储分配所做的任何更改MTLCommandBuffer。也就是说,MTLDevice对象可能不会观察到主机CPU在MTLCommandBuffer对象被提交后所做的资源的更改(即对象的status属性)。MTLCommandBufferMTLCommandBufferStatusCommitted

类似地,在MTLDevice对象执行MTLCommandBuffer对象之后,MTLDevice如果命令缓冲区已经完成执行(即,对象的status属性),则主机CPU只能保证观察对象对该命令缓冲区引用的任何资源的存储分配的任何更改MTLCommandBuffer是MTLCommandBufferStatusCompleted)。

下一页

上一页

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容