資源對象:緩沖區(qū)和紋理
本章介紹MTLResource用于存儲未格式化存儲器和格式化圖像數(shù)據(jù)的
Metal資源對象(MTLResource)。有兩種類型的MTLResource對象:
MTLBuffer表示可以包含任何類型數(shù)據(jù)的未格式化內(nèi)存的分配泽台。
緩沖區(qū)通常用于頂點喂江,著色器和計算狀態(tài)數(shù)據(jù)隐锭。MTLTexture表示具有指定紋理類型和像素格式的格式化圖像數(shù)據(jù)的分配晒杈。紋理對象用作頂點,片段或計算函數(shù)的源紋理方椎,以及存儲圖形渲染輸出(即附件)聂抢。
MTLSamplerState本章還討論了對象。雖然采樣器本身不是資源棠众,但是在使用紋理對象執(zhí)行查找計算時會使用它們涛浙。
緩沖區(qū)是無類型的內(nèi)存分配
一個MTLBuffer對象表示的存儲器的分配,它可以包含任何類型的數(shù)據(jù)。
創(chuàng)建緩沖區(qū)對象
以下MTLDevice方法創(chuàng)建并返回一個MTLBuffer對象:
該newBufferWithLength:options:方法創(chuàng)建一個MTLBuffer新的存儲分配對象轿亮。
該newBufferWithBytes:length:options:方法MTLBuffer通過將來自現(xiàn)有存儲(位于CPU地址pointer)的數(shù)據(jù)復制到新的存儲分配中來創(chuàng)建對象疮薇。
該newBufferWithBytesNoCopy:length:options:deallocator:方法創(chuàng)建MTLBuffer具有現(xiàn)有存儲分配的對象,并且不會為此對象分配任何新存儲我注。
所有緩沖區(qū)創(chuàng)建方法都有輸入值length來指示存儲分配的大邪粗洹(以字節(jié)為單位)。所有的方法也接受一個MTLResourceOptions對象options但骨,可以修改創(chuàng)建的緩沖區(qū)的行為励七。如果值為options0,則默認值用于資源選項奔缠。
緩沖方法
該MTLBuffer協(xié)議具有以下的方法:
該contents方法返回緩沖區(qū)的存儲分配的CPU地址掠抬。
該newTextureWithDescriptor:offset:bytesPerRow:方法創(chuàng)建引用緩沖區(qū)數(shù)據(jù)的特殊類型的紋理對象。此方法在創(chuàng)建紋理對象中有詳細說明校哎。
紋理是格式化的圖像數(shù)據(jù)
一個MTLTexture對象表示可被用作用于頂點著色器資源两波,片段著色器,或計算功能格式化的圖像數(shù)據(jù)的分配闷哆,或者作為附件被用作渲染目的地腰奋。一個MTLTexture對象可以有一個以下結構:
1D,2D或3D圖像
一維或二維圖像陣列
一個立方體六個2D圖像
MTLPixelFormat指定MTLTexture對象中各個像素的組織抱怔。像素格式在“ 像素格式”進一步討論劣坊。
創(chuàng)建一個紋理對象
以下方法創(chuàng)建并返回一個MTLTexture對象:
用紋理圖像數(shù)據(jù)創(chuàng)建一個新的存儲分配對象的newTextureWithDescriptor:方法,使用對象來描述紋理的屬性屈留。MTLDevice MTLTextureMTLTextureDescriptor
所述newTextureViewWithPixelFormat:的方法MTLTexture創(chuàng)建一個
MTLTexture共享相同的存儲分配作為調(diào)用對象MTLTexture的對象局冰。由于它們共享相同的存儲,所以對新的紋理對象的像素的任何改變都會反映在調(diào)用紋理對象中灌危,反之亦然锐想。對于新創(chuàng)建的紋理,該newTextureViewWithPixelFormat:方法重新解釋調(diào)用MTLTexture
對象的存儲分配的現(xiàn)有紋理圖像數(shù)據(jù)乍狐,就像數(shù)據(jù)以指定的像素格式存儲一樣赠摇。在MTLPixelFormat新的紋理對象必須是兼容與MTLPixelFormat原始紋理的對象。(有關普通浅蚪,打包和壓縮像素格式的詳細信息藕帜,請參閱紋理的像素格式。)所述newTextureWithDescriptor:offset:bytesPerRow:的方法MTLBuffer創(chuàng)建一個MTLTexture共享主叫的存儲分配對象MTLBuffer對象作為其紋理圖像數(shù)據(jù)惜傲。當它們共享相同的存儲時洽故,對新的紋理對象的像素的任何改變都反映在調(diào)用紋理對象中,反之亦然盗誊。在紋理和緩沖區(qū)之間共享存儲可以阻止使用某些紋理優(yōu)化时甚,例如像素閃爍或平鋪隘弊。
使用紋理描述符創(chuàng)建紋理對象
MTLTextureDescriptor定義用于創(chuàng)建MTLTexture對象的屬性,包括其圖像大谢氖省(寬度梨熙,高度和深度),像素格式刀诬,排列(陣列或多維數(shù)據(jù)集類型)和mipmap的數(shù)量咽扇。的MTLTextureDescriptor屬性創(chuàng)建一個的過程中僅使用MTLTexture對象。創(chuàng)建MTLTexture對象后陕壹,其MTLTextureDescriptor對象中的屬性更改對該紋理不再有任何影響质欲。
從描述符創(chuàng)建一個或多個紋理:
1 :創(chuàng)建MTLTextureDescriptor包含描述紋理數(shù)據(jù)的紋理屬性的自定義對象:
- 該textureType屬性指定紋理的維度和排列(例如,數(shù)組或多維數(shù)據(jù)集)糠馆。
- the width坛悉,heightand和depthproperties指定基本級別紋理mipmap的每個維度中的像素大小系忙。
- 該pixelFormat屬性指定像素如何存儲在紋理中屿衅。
- 該arrayLength屬性指定一個MTLTextureType1DArray或MTLTextureType2DArray類型的紋理對象的數(shù)組元素的數(shù)量憾赁。
- 該mipmapLevelCount屬性指定mipmap級別的數(shù)量。
- 該sampleCount屬性指定每個像素中的樣本數(shù)赠橙。
- 該resourceOptions屬性指定其內(nèi)存分配的行為耽装。
2:MTLTextureDescriptor通過調(diào)用對象的newTextureWithDescriptor:方法從對象創(chuàng)建一個紋理MTLDevice愤炸。在紋理創(chuàng)建之后期揪,調(diào)用replaceRegion:mipmapLevel:slice:withBytes:bytesPerRow:bytesPerImage:方法來加載紋理圖像數(shù)據(jù),如將紋理圖像數(shù)據(jù)復制到紋理中所詳述的规个。
3:要創(chuàng)建更多的MTLTexture對象凤薛,可以重用同一個MTLTextureDescriptor對象,根據(jù)需要修改描述符的屬性值诞仓。
清單3-1顯示了用于創(chuàng)建紋理描述符txDesc并為3D缤苫,64x64x64紋理設置其屬性的代碼。
清單3-1 使用自定義紋理描述符創(chuàng)建紋理對象
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的大小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級別是第一個實現(xiàn)大小為1 x 1 x 1的mipmap級別。
在一個切片的mipmap級的數(shù)目可以按樓層來確定(日志2(MAX( 唤蔗,width探遵,height)))+depth 1窟赏。
所有紋理對象至少有一個切片; 立方體和數(shù)組紋理類型可能有幾個切片。在寫入和讀取紋理圖像數(shù)據(jù)的方法中箱季,將紋理圖像數(shù)據(jù)復制到紋理和從紋理復制圖像數(shù)據(jù)涯穷,slice是一個基于零的輸入值。對于1D规哪,2D或3D紋理求豫,只有一個切片,因此值slice必須為0.立方體紋理具有六個總的2D切片诉稍,從0到5尋址蝠嘉。對于1DArray和2DArray紋理類型,每個數(shù)組元素代表一片杯巨。例如蚤告,對于具有arrayLength= 10 的2DArray紋理類型,有10個總片服爷,從0到9尋址杜恰。要從整體紋理結構中選擇單個1D,2D或3D圖像仍源,首先選擇一個片段心褐,然后選擇該片段中的mipmap級別。
用方便的方法創(chuàng)建紋理描述符
對于常見的2D和多維數(shù)據(jù)集紋理笼踩,請使用以下便利方法創(chuàng)建一個MTLTextureDescriptor對象逗爹,其中的幾個屬性值自動設置:
該texture2DDescriptorWithPixelFormat:width:height:mipmapped:
方法MTLTextureDescriptor為2D紋理創(chuàng)建一個對象。的width和height值定義了2D紋理的尺寸嚎于。該type屬性被自動設置為MTLTextureType2D掘而,并且depth和arrayLength被設置為1。該textureCubeDescriptorWithPixelFormat:size:mipmapped:方法創(chuàng)建一個MTLTextureDescriptor用于立方織構于购,其中所述對象type屬性設置為MTLTextureTypeCube袍睡,width和height被設置為大小,depth并且arrayLength被設置為1肋僧。
兩種MTLTextureDescriptor方便的方法都接受一個輸入值斑胜,pixelFormat它定義了紋理的像素格式。兩種方法也接受輸入值mipmapped嫌吠,該值決定紋理圖像是否被映射止潘。(如果mipmapped是YES,紋理是mipmap居兆。)
清單3-2使用該texture2DDescriptorWithPixelFormat:width:height:mipmapped:方法64x64為未映射的2D紋理創(chuàng)建描述符對象覆山。
清單3-2 使用方便的紋理描述符創(chuàng)建紋理對象
MTLTextureDescriptor * texDesc = [MTLTextureDescriptor
texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
width:64 height:64 mipmapped:NO];
id <MTLTexture> myTexture = [device newTextureWithDescriptor:texDesc];
從紋理復制圖像數(shù)據(jù)
要將圖像數(shù)據(jù)同步復制到或從MTLTexture對象的存儲分配中復制數(shù)據(jù),請使用以下方法:
replaceRegion:mipmapLevel:slice:withBytes:bytesPerRow:bytesPerImage:將來自調(diào)用者指針的像素數(shù)據(jù)的區(qū)域復制到指定紋理片的存儲分配的一部分中泥栖。replaceRegion:mipmapLevel:withBytes:bytesPerRow:是類似的便利方法簇宽,將像素數(shù)據(jù)區(qū)域復制到默認切片中勋篓,假設切片相關參數(shù)的默認值(即slice= 0和bytesPerImage= 0)。
getBytes:bytesPerRow:bytesPerImage:fromRegion:mipmapLevel:slice:從指定的紋理切片檢索像素數(shù)據(jù)的區(qū)域魏割。getBytes:bytesPerRow:fromRegion:mipmapLevel:是類似的便利方法譬嚣,從默認切片中檢索像素數(shù)據(jù)的區(qū)域,假設切片相關參數(shù)(slice= 0和bytesPerImage= 0)的默認值钞它。
清單3-3顯示了如何replaceRegion:mipmapLevel:slice:withBytes:bytesPerRow:bytesPerImage:從系統(tǒng)內(nèi)存textureData中的slice 0和mipmap級別的源數(shù)據(jù)中調(diào)用指定紋理圖像0拜银。
清單3-3 將圖像數(shù)據(jù)復制到紋理中
// 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對象的各個像素中的顏色,深度和模板數(shù)據(jù)存儲的組織遭垛。像素格式有三種:普通尼桶,打包,壓縮锯仪。
普通格式只有常規(guī)的8位泵督,16位或32位顏色組件。每個組件被布置在增加的存儲器地址中庶喜,其中第一個列出的組件處于最低地址小腊。例如,MTLPixelFormatRGBA8Unorm是一個32位格式久窟,每個顏色分量有8位; 最低的地址包含紅色秩冈,下一個地址包含綠色,依此類推斥扛。相比之下入问,對于MTLPixelFormatBGRA8Unorm,最低的地址包含藍色犹赖,下一個地址包含綠色队他,依此類推卷仑。
打包格式將多個組件組合成一個16位或32位值峻村,其中組件從最低位到最高有效位(LSB到MSB)存儲。例如锡凝,MTLPixelFormatRGB10A2Uint是一個32位打包格式粘昨,由三個10位通道(用于R,G和B)和兩位用于alpha窜锯。
壓縮格式以像素塊排列张肾,每個塊的布局特定于該像素格式。壓縮像素格式只能用于2D锚扎,2D陣列或多維數(shù)據(jù)集紋理類型吞瞪。壓縮的格式不能用于創(chuàng)建1D,2DMultisample或3D紋理驾孔。
該MTLPixelFormatGBGR422和MTLPixelFormatBGRG422是被用于存儲像素的YUV色彩空間特殊的像素格式芍秆。這些格式僅支持2D紋理(但不包括2D數(shù)組惯疙,也不是立方體類型),沒有mipmap妖啥,甚至是偶數(shù)width霉颠。
幾個像素格式存儲具有sRGB顏色空間值的顏色組件(例如,MTLPixelFormatRGBA8Unorm_sRGB或MTLPixelFormatETC2_RGB8_sRGB)荆虱。當采樣操作以sRGB像素格式引用紋理時蒿偎,Metal實現(xiàn)在采樣操作發(fā)生之前將sRGB顏色空間分量轉換為線性顏色空間。從sRGB組件S到線性分量L的轉換如下所示:
如果S <= 0.04045怀读,L = S / 12.92
如果S> 0.04045诉位,L =((S + 0.055)/1.055)^2.4
相反,當渲染到使用具有sRGB像素格式的紋理的可呈現(xiàn)顏色的附件時菜枷,實現(xiàn)將線性顏色值轉換為sRGB不从,如下所示:
如果L <= 0.0031308,則S = L * 12.92
如果L> 0.0031308犁跪,S =(1.055 * L 0.41667)^-0.055
有關渲染的像素格式的更多信息椿息,請參閱創(chuàng)建渲染通過描述符。
創(chuàng)建用于紋理查找的采樣器狀態(tài)對象
一個MTLSamplerState對象定義了圖形或計算函數(shù)對MTLTexture對象執(zhí)行紋理采樣操作時使用的尋址坷衍,過濾和其他屬性寝优。采樣器描述符定義采樣器狀態(tài)對象的屬性。要創(chuàng)建采樣器狀態(tài)對象:
1: 調(diào)用對象的newSamplerStateWithDescriptor:方法MTLDevice來創(chuàng)建一個MTLSamplerDescriptor對象枫耳。
2:在MTLSamplerDescriptor對象中設置所需的值乏矾,包括過濾選項,尋址模式迁杨,最大各向異性和詳細級參數(shù)钻心。
3:MTLSamplerState通過調(diào)用創(chuàng)建描述符newSamplerStateWithDescriptor:的MTLDevice對象的方法,從采樣器描述符創(chuàng)建一個對象铅协。
您可以重用采樣器描述符對象來創(chuàng)建更多的MTLSamplerState對象捷沸,根據(jù)需要修改描述符的屬性值。描述符的屬性僅在對象創(chuàng)建過程中使用狐史。在創(chuàng)建采樣器狀態(tài)之后痒给,更改其描述符中的屬性將不再對該采樣器狀態(tài)產(chǎn)生影響。
清單3-4是一個代碼示例骏全,它創(chuàng)建MTLSamplerDescriptor并配置它以創(chuàng)建一個MTLSamplerState苍柏。非默認值為描述符對象的過濾器和地址模式屬性設置。然后該newSamplerStateWithDescriptor:方法使用采樣器描述符來創(chuàng)建采樣器狀態(tài)對象姜贡。
清單3-4 創(chuàng)建采樣器狀態(tài)對象
//創(chuàng)建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;
//創(chuàng)建MTLSamplerState
id <MTLSamplerState> sampler = [device newSamplerStateWithDescriptor:desc];
保持CPU和GPU內(nèi)存之間的一致性
CPU和GPU都可以訪問MTLResource對象的底層存儲试吁。但是,GPU從主機CPU異步運行楼咳,因此在使用主機CPU訪問這些資源的存儲時熄捍,請注意以下幾點律秃。
執(zhí)行MTLCommandBuffer對象時,MTLDevice只有在對象提交之前(并且只有這些更改)由主機CPU進行時治唤,對象才能保證觀察到主機CPU對MTLResource由該MTLCommandBuffer對象引用的任何對象的存儲分配所做的任何更改MTLCommandBuffer棒动。也就是說,MTLDevice對象可能不會觀察到主機CPU在MTLCommandBuffer對象被提交后所做的資源的更改(即對象的status屬性)宾添。MTLCommandBufferMTLCommandBufferStatusCommitted
類似地船惨,在MTLDevice對象執(zhí)行MTLCommandBuffer對象之后,MTLDevice如果命令緩沖區(qū)已經(jīng)完成執(zhí)行(即缕陕,對象的status屬性)粱锐,則主機CPU只能保證觀察對象對該命令緩沖區(qū)引用的任何資源的存儲分配的任何更改MTLCommandBuffer是MTLCommandBufferStatusCompleted)。