分析Unity在移動(dòng)設(shè)備的GPU內(nèi)存機(jī)制(iOS篇)

問題

開發(fā)手機(jī)游戲時(shí)勾笆,常聽到身邊的人傳授經(jīng)驗(yàn):“CPU和GPU是共享一份內(nèi)存的”梧宫,但這句經(jīng)驗(yàn)到底具體指的是什么橡类,仿佛總得不到細(xì)節(jié)精確的回答蛇尚。

因此,本文嘗試以一張貼圖紋理的虛擬內(nèi)存占用為例顾画,就以下問題進(jìn)行分析和解答:

  1. 是否的確主存顯存共享一份貼圖虛擬內(nèi)存取劫?
  2. 如果問題1證實(shí)的確只有一份,紋理虛擬內(nèi)存的完整流程是怎樣研侣?Unity將該紋理文件在主存加載好紋理數(shù)據(jù)后:
    2.1.直接調(diào)用圖形API傳遞該主存指針谱邪,從而GPU能直接訪問該主存中的紋理數(shù)據(jù)?
    2.2. 還是需要調(diào)用圖形API將該主存中的紋理數(shù)據(jù)拷貝到另一份虛擬內(nèi)存中庶诡,以供GPU訪問惦银?拷貝完成后紋理主存部分如何處置?

術(shù)語

為清晰表達(dá)避免概念混淆灌砖,本文采取以下術(shù)語:
物理內(nèi)存(Physical Memory):具體的存儲(chǔ)硬件璧函,各種SDRAM,比如LPDDR是移動(dòng)設(shè)備常用的一種低功耗SDRAM基显。
虛擬內(nèi)存(Virtual Memory):對(duì)物理內(nèi)存的一種邏輯映射蘸吓。
系統(tǒng)內(nèi)存(System Memory/Primary Memory):CPU能讀寫的虛擬內(nèi)存。
顯存(Graphics Memory):GPU能讀寫的虛擬內(nèi)存撩幽。

另外库继,外存(External storage):外部存儲(chǔ),“硬盤”窜醉,在移動(dòng)設(shè)備一般是Flash宪萄。

iOS篇

硬件

如下4圖[1][2]所示,iPhone6只有A8里擁有一塊物理內(nèi)存(1GB LPDDR3 RAM)榨惰,且CPU/GPU晶片中并無物理內(nèi)存(SDRAM)拜英,只有物理內(nèi)存的接口(SDRAM Interface)。
且A8采取PoP封裝(Package on Package)琅催,即將CPU/GPU晶片和物理內(nèi)存豎直排列于A8芯片中居凶,將CPU/GPU晶片移除后,在下一層露出了它倆共用的一塊物理內(nèi)存藤抡。
注侠碧,晶片中有高速Cache緩存,類型為SRAM缠黍。

iPhone6的物理內(nèi)存位于Apple A8里

Apple A8 晶片里弄兜,只有SDRAM的接口,并無SDRAM

A8 GPU PowerVR 6450里只有System Memory Interface,并無SDRAM

A8 SoC CPU/GPU晶片 和 物理內(nèi)存采取PoP封裝替饿。將CPU/GPU晶片從SoC移除后语泽,露出下一層的DRAM物理內(nèi)存

其他iOS設(shè)備,iPhone盛垦、iPad等湿弦,亦如此,硬件層面腾夯,它們的物理內(nèi)存都為統(tǒng)一內(nèi)存(Unified Memory)架構(gòu)颊埃,即主存和顯存都位于同樣的物理內(nèi)存硬件中。

而桌面電腦一般是分離物理內(nèi)存(Discrete Memory)架構(gòu)蝶俱。

圖形API

自2013年的AppleA7(iPhone 5s)起iOS設(shè)備便支持Metal[3]班利,考慮當(dāng)下(2018)的市場(chǎng)份額,故只討論支持Metal的情況榨呆,而不討論iOS上OpenGLES的情況罗标。

系統(tǒng)層面,Metal支持主存顯存同時(shí)訪問同一塊虛擬內(nèi)存积蜻,即MTLBuffer的options為MTLStorageModeShared[4,5,6]闯割,此情況已無主存顯存之分,Shared模式是Buffer(比如頂點(diǎn)緩存竿拆、索引緩存)的默認(rèn)創(chuàng)建模式宙拉,在iOS中Shared也是紋理緩存的默認(rèn)創(chuàng)建模式。

Resource storage modes in iOS and tvOS

此時(shí)對(duì)該虛擬內(nèi)存的修改丙笋,會(huì)同時(shí)反饋到CPU和GPU上谢澈,除非CPU準(zhǔn)備好Buffer的內(nèi)容后不再修改,但一旦CPU對(duì)Buffer進(jìn)行了二次修改御板,為避免和GPU的訪問沖突锥忿,需要有一定的同步機(jī)制,比如三重緩沖(Tripple Buffering)[7]怠肋。
Pirvate模式為GPU單獨(dú)訪問的虛擬內(nèi)存敬鬓,主要用于RenderTexture等情況[9],并非當(dāng)前重點(diǎn)笙各。

分析Unity在iOS的實(shí)現(xiàn)

雖然圖形API機(jī)制如此钉答,但不同引擎內(nèi)部實(shí)現(xiàn)大相徑庭,保守起見酪惭,具體結(jié)論應(yīng)以引擎具體邏輯為準(zhǔn)希痴。
先以紋理為例者甲,Unity在iOS+Metal上從紋理文件存儲(chǔ)到最終紋理顯存春感,其二進(jìn)制流的完整流程是怎樣的?
人肉閱讀分析Unity源碼是耗時(shí)且可能不準(zhǔn)確的。結(jié)合Profiler等工具進(jìn)行分析鲫懒,會(huì)省時(shí)精確嫩实,事半功倍。這樣也可順帶對(duì)Profile工具的綜合應(yīng)用進(jìn)行介紹窥岩。所以下面甲献,先假設(shè)我們不知道Metal的機(jī)制,試從現(xiàn)象推斷出原因颂翼。


GFXMemory測(cè)試Demo

先創(chuàng)建一個(gè)名為GFXMemory的測(cè)試demo晃洒,分別有3張分辨率足夠大的4096x4096的紋理貼圖,格式分別設(shè)為RGBA32朦乏、RGB24球及、ASTC5x5,通過運(yùn)行時(shí)點(diǎn)擊對(duì)應(yīng)的區(qū)域呻疹,才單獨(dú)加載對(duì)應(yīng)貼圖吃引,顯示在屏幕中。

準(zhǔn)備做Profile測(cè)試先查證以下問題:
由于3張紋理分辨率非常大且開啟Mipmaps刽锤,其內(nèi)存占用理應(yīng)是期待紋理虛擬內(nèi)存 = 85.33MB + 64.00MB + 13.65MB = 162.98MB镊尺,如果最終內(nèi)存穩(wěn)定后,本進(jìn)程的虛擬內(nèi)存占用約為進(jìn)程內(nèi)存 ~= 啟動(dòng)內(nèi)存 + 已加載紋理內(nèi)存并思,即可證實(shí)紋理虛擬內(nèi)存占用的確只有一份庐氮,否則如果進(jìn)程虛擬內(nèi)存約為進(jìn)程內(nèi)存 ~= 啟動(dòng)內(nèi)存 + 2*已加載紋理內(nèi)存,即可證實(shí)主存纺荧、顯存各持一份紋理貼圖旭愧。

Unity版本為2017.4.8f1、XCode版本為10.1宙暇、運(yùn)行設(shè)備為iPhone6s输枯。
先用Unity以Development Build進(jìn)行XCode工程導(dǎo)出,Development Build僅僅是為了能用Unity Memory Profiler進(jìn)行Profile占贫。
XCode中對(duì)Unity-iPhone工程進(jìn)行Edit Scheme桃熄,并如下圖開啟Malloc Stack,是為了在命令行對(duì)memorygraph使用malloc_history命令查看內(nèi)存創(chuàng)建的堆棧型奥。

開啟Malloc Stack才能對(duì)memorygraph方能使用malloc_history命令查看內(nèi)存創(chuàng)建的堆棧

XCode中構(gòu)建版本瞳收,USB連接iPhone6s并在其上運(yùn)行,等待幾秒鐘待內(nèi)存穩(wěn)定后:

  • 在XCode點(diǎn)擊“Debug Memory Graph”厢汹,截取得出XCode的內(nèi)存統(tǒng)計(jì)螟深,并且Export為xcode_empty.memorygraph文件

點(diǎn)擊UI加載上面3張紋理后,等待幾秒鐘待內(nèi)存穩(wěn)定后:

  • 在Unity用Memory Profiler點(diǎn)擊Take Snapshot烫葬,截取得出Unity的內(nèi)存統(tǒng)計(jì)界弧,并另存為unity.memsnap3文件
  • 在XCode點(diǎn)擊“Capture GPU Frame”凡蜻,截取得到當(dāng)前幀的GPU快照,并另存為xcode.gputrace文件
  • 在XCode點(diǎn)擊“Debug Memory Graph”垢箕,截取得出XCode的內(nèi)存統(tǒng)計(jì)划栓,并且Export為xcode.memorygraph文件

注意上述操作都確保游戲是一次運(yùn)行針對(duì)同一進(jìn)程的4次抓取結(jié)果,從而確保內(nèi)存地址穩(wěn)定条获。

我們?cè)诿钚袌?zhí)行命令vmmap --summary ./xcode_empty.memgraph忠荞,得到加載紋理前的虛擬內(nèi)存占用約為111.3MB,如下圖:

加載紋理前帅掘,Native虛擬內(nèi)存占用約為111.3MB

上圖我們應(yīng)關(guān)心“DIRTY SIZE”和“SWAPPED SIZE”委煤,前者代表已寫虛存大小、后者代表已寫待壓縮虛存大小修档。iOS和一般OS不一樣素标,不采取虛存切頁(Paging)的機(jī)制,而是采取壓縮內(nèi)存的機(jī)制萍悴。而在iOS中所謂的內(nèi)存占用(Memory Footprint)事實(shí)上是MemoryFootprint = DirtySize + CompressedSize头遭,iOS以MemoryFootprint的大小作為Killapp的依據(jù)。注意Swapped Size是待壓縮的大小癣诱,壓縮后方為Compressed Size计维。[8]

Memory Footprint = Dirty Size + Compressed Size

我們?cè)賵?zhí)行命令vmmap --summary ./xcode.memgraph,得到加載紋理后的虛擬內(nèi)存占用約為297.8MB撕予,如下圖:

加載紋理后鲫惶,Native虛擬內(nèi)存占用約為297.8MB

從而,加載紋理額外虛擬內(nèi)存占用 = 297.9MB - 111.3MB = 186.6MB ~= 期待紋理虛擬內(nèi)存占用162.98MB实抡,而186.6MB << 325.96MB欠母,從而幾乎已經(jīng)證實(shí)問題1,的確主存顯存共享一份貼圖虛擬內(nèi)存吆寨。至于為何會(huì)多出186.6MB - 162.98MB ~= 23.62MB赏淌,我們會(huì)在后面證實(shí)到。

但僅僅從內(nèi)存增幅來認(rèn)定內(nèi)存共享一份啄清,顯得還不夠精確六水。

這時(shí)有個(gè)貌似合理的猜想:“如果GPU里用到的紋理虛擬內(nèi)存地址,剛好等于MemoryGraph中對(duì)應(yīng)的紋理虛擬地址辣卒,就說明它們必然是共享一份內(nèi)存了”掷贾。
懷著這個(gè)想法,我們用XCode打開xcode.gputrace文件荣茫,搜索得出4096_rgba32的虛擬內(nèi)存地址為0x1083f5b80想帅,如下圖:


GPUTrace文件顯示4096_rgba32紋理的虛擬內(nèi)存地址為0x1083f5b80

Unity Memory Profiler Editor本不支持顯示對(duì)象的Native虛擬內(nèi)存地址,簡(jiǎn)單修改其源碼啡莉,讓其在面板上顯示Unity Native Object的虛擬內(nèi)存地址港准,4096_rgba32紋理的虛擬內(nèi)存地址為0x1083f53b0紋理憎乙,如下圖:


Unity Memory Profiler顯示4096_rgba32紋理的虛擬內(nèi)存地址為0x1083f53b0

“CPU/GPU訪問的紋理地址不一樣,這證實(shí)這張紋理不是CPU/GPU共享的叉趣!”但可惜,不能因此得出這個(gè)結(jié)論该押。
我們控制臺(tái)針對(duì)GPUTrace的地址使用命令malloc_history ./xcode.memgraph -fullStacks 0x1083f5b80疗杉,有下圖輸出:

GPUTrace紋理對(duì)象AGXA9FamilyTexture地址的堆分配函數(shù)棧

針對(duì)Unity Memory Profiler的地址使用命令malloc_history ./xcode.memgraph -fullStacks 0x1083f53b0,有下圖輸出:
Unity Memory Profiler紋理對(duì)象Texture2D地址的堆分配函數(shù)棧

使用XCode再次打開xcode.memgraph蚕礼,搜索地址0x1083f5b80烟具,發(fā)現(xiàn)其類型是“AGXA9FamilyTexture”,而且對(duì)象大小僅僅只有528字節(jié)奠蹬,見下圖:


0x1083f5b80地址對(duì)應(yīng)的朝聋,僅僅是紋理對(duì)象,而并非我們最關(guān)心的紋理內(nèi)容

上面3圖囤躁,證實(shí)了上面的地址僅僅是紋理對(duì)象冀痕,而并非我們最關(guān)心的紋理內(nèi)容地址。比如AGXA9FamilyTexture是Metal的紋理對(duì)象狸演,Texture2D是Unity的紋理對(duì)象言蛇,紋理對(duì)象內(nèi)部有指針指向了紋理內(nèi)容。

如果我們不修改Unity源碼宵距,我們無法得知Texture2D中紋理內(nèi)容的地址腊尚。如何得知紋理內(nèi)容到底在哪呢?

留意上面vmmap --summary命令顯示加載紋理前后的內(nèi)存占用满哪,增幅最大的內(nèi)存區(qū)域(Region)是“IOKit”婿斥,我們不妨看看里面到底是啥,通過vmmap --verbose ./xcode.memgraph | grep "IOKit"哨鸭,有以下結(jié)果:

IOKit內(nèi)存區(qū)域里民宿,有明顯的貼圖內(nèi)容虛擬內(nèi)存占用

上面非常像我們3張紋理貼圖內(nèi)容的內(nèi)存占用大小(下面才解釋為什么64.0MB變?yōu)?5.3MB)像鸡,而左邊就是它們的虛擬內(nèi)存地址勘高。
我們嘗試用malloc_history ./xcode.memgraph --fullStacks “上述3個(gè)地址”,發(fā)現(xiàn)都不能打印出分配它們的棧坟桅,說明它們并非使用傳統(tǒng)malloc在堆(Heap)上分配华望,如下圖。事實(shí)上IOKit是iOS的驅(qū)動(dòng)框架仅乓,該區(qū)域內(nèi)存是驅(qū)動(dòng)相關(guān)的虛擬內(nèi)存區(qū)域赖舟,通過額外的實(shí)驗(yàn)可以知道,Metal最重要的MTLBuffer分配夸楣,不管Dirty與否宾抓,都是在IOKit這個(gè)驅(qū)動(dòng)區(qū)域進(jìn)行內(nèi)存分配子漩。

IOKit區(qū)域是驅(qū)動(dòng)相關(guān)的虛擬內(nèi)存地址,并不能通過malloc_history打印出來

但是石洗!當(dāng)我們?cè)赬Code打開xcode.memgraph后幢泼,如下圖,搜索地址“0x11c3e0000”得出該85.3MB的IOKit內(nèi)存讲衫,而引用它的缕棵,恰好就是我們上面發(fā)現(xiàn)的地址為0x1083f5b80的Metal的紋理對(duì)象!


至此涉兽,我們通過硬件分析招驴、圖形API分析和虛擬內(nèi)存Profile分析,比較折騰枷畏,終于得出以下結(jié)論:

  • iOS設(shè)備中只有一塊物理內(nèi)存硬件
  • 主存地址和顯存地址在同一個(gè)地址空間(Address Space)中别厘,即虛存地址空間(Virtual Address Space)
  • 虛擬內(nèi)存中的確只有一份紋理內(nèi)容,而且該紋理內(nèi)容的確就是被GPU所用的紋理拥诡。

我們接著討論問題2触趴。由于問題2需要回答的是貼圖內(nèi)存走向,不能通過分析某一時(shí)刻的虛擬內(nèi)存得出結(jié)論渴肉,而要使用帶有Timeline的Profiler雕蔽,這里使用Instruments。
我們進(jìn)行3種Profiler:Timer Profiler以觀察CPU耗時(shí)情況及捕捉函數(shù)調(diào)用棧宾娜,Allocations以觀察堆內(nèi)存分配釋放情況批狐,VM Tracker以觀察所有虛擬內(nèi)存的分配釋放情況。
針對(duì)Time Profiler前塔,我們可以打開其High Frequency選項(xiàng)嚣艇,以采樣到更精細(xì)的函數(shù)調(diào)用棧。


打開Time Profiler的High Frequency华弓,以捕捉到更精細(xì)的函數(shù)調(diào)用棧

Profile結(jié)果如下圖食零。其中3個(gè)紅框左到右分別表示加載RGBA32、RGB24寂屏、ASTC5x5時(shí)的情況贰谣。

進(jìn)行Time Profiler、Allocations迁霎、VM Tracker的Profiler吱抚,圖中3個(gè)紅框分別是加載RGBA_32、RGB24考廉、ASTC5x5時(shí)的情況

大致觀察上圖可以發(fā)現(xiàn):

  • CPU消耗尖刺(Spike):RGB24 > RGBA32 >> ASTC5x5
  • 堆內(nèi)存消耗尖刺:RGB24 > RGB32 >> ASTC5x5
  • 虛擬內(nèi)存消耗則整體呈現(xiàn)持續(xù)增長

我們先看最左邊RGBA32的CPU消耗情況秘豹,如下兩圖,分別為加載RGB24紋理時(shí)CPU消耗Spike的前期和后期


加載RGB24紋理時(shí)CPU消耗Spike的前期

加載RGB24紋理時(shí)CPU消耗Spike的后期

不需無頭緒地辛苦閱讀海量引擎代碼昌粤,有的放矢既绕,立刻可精確看出Unity在加載紋理時(shí)主要工作分兩部分:文件加載(File::Read())和紋理上傳(UploadTexture2DData())啄刹。
而且發(fā)現(xiàn)將時(shí)間線在前后期中間不管如何細(xì)分,都只出現(xiàn)了上面2個(gè)主要消耗凄贩,說明了只有這兩個(gè)工作線程在工作誓军,我們只需分析它們相信已足夠找出紋理加載的流程。我們也發(fā)現(xiàn)在整個(gè)紋理加載過程中疲扎,主線程只有非常少的Update空轉(zhuǎn)占用昵时,證實(shí)紋理加載幾乎是脫離主線程工作的。

文件加載函數(shù)椘浪粒看起來比較通用,先從紋理上傳的函數(shù)椃乔看起應(yīng)該會(huì)更快解決問題瓜挽。可發(fā)現(xiàn)其關(guān)鍵流程如下:

<具體分析略>

通過以上比較啰嗦的分析征绸,可以看出就算是在Metal進(jìn)行紋理上傳久橙,也難免有紋理內(nèi)容拷貝的過程。用[MTLDevice newTextureWithDescriptor]創(chuàng)建紋理對(duì)象及其指向的紋理內(nèi)容空間管怠,把FileAssetUploadInstructionbuffer數(shù)據(jù)淆衷,加以一定處理(Crunch、紋理格式轉(zhuǎn)換等)渤弛,最終通過[MTLTexture replaceRegion]將紋理內(nèi)容數(shù)據(jù)拷貝到了驅(qū)動(dòng)虛擬內(nèi)存IOKit區(qū)域里祝拯。

那到底這個(gè)buffer數(shù)據(jù)到底從哪來的?當(dāng)然她肯,從上文和類名包含“File”佳头,已經(jīng)可以猜出是從外存讀取得來,但不精確證實(shí)不服氣晴氨,我們將注意力回到上面的文件加載調(diào)用棧。堆棧協(xié)助代碼閱讀,發(fā)現(xiàn)很簡(jiǎn)單:

<具體分析略>

那么command->buffer的內(nèi)存哪里分配而來呢密浑?

由于內(nèi)存分配的CPU消耗可能很小付燥,就算是高精度的Sampler也可能在Time Profiler里找不到,這里我們明顯要求救于Allocation枝哄,如下圖肄梨,我們選擇“Call Trees”分類,框選在加載紋理時(shí)挠锥,內(nèi)存飆升時(shí)的時(shí)段峭范,發(fā)現(xiàn)132.03MB內(nèi)存是在AsyncUploadManager::ManageTextureUploadRingBufferMemory()中分配給m_DataRingBuffer

文件讀取的緩存應(yīng)該是在堆上分配

AsyncUploadManager::ManageTextureUploadRingBufferMemory()圖略 )

紋理上傳過程中,最大的堆內(nèi)存分配是分配給了AyncUploadManager.m_DataRingBuffer

通過以上種種分析瘪贱,已經(jīng)掌握了不少信息和關(guān)鍵字纱控,找出答案已是臨門一腳了:

AsyncUploadManager::AcquireWritePtr()圖略 )

AsyncUploadManager::ScheduleAsyncRead()m_DataRingBuffer申請(qǐng)紋理內(nèi)容大小的內(nèi)存空間辆毡,同時(shí)將指針賦值給asyncReadCommand->bufferftuInstr->buffer,從而文件讀取線程將紋理文件內(nèi)容寫到asyncReadCommand->buffer指向的堆內(nèi)存甜害,渲染線程在通過ftuInstr->buffer將紋理內(nèi)容從同一堆內(nèi)存獲取到舶掖。

至此,回答了問題2尔店。

最后的最后眨攘,上面提到的RGB24紋理的特殊情況,為什么其虛擬內(nèi)存占用大小不是64MB嚣州,而是和RGBA32一樣鲫售,都是85.3MB?結(jié)合上面已知流程该肴,分析可知情竹,原因是Metal并不支持RGB24,在運(yùn)行時(shí)都會(huì)轉(zhuǎn)為RGBA32匀哄,如下:

metal::PixelFormat圖略 )

這能從以下Time Profiler以及Allocation棧輕易證實(shí):

Metal不支持RGB24秦效,交給GPU使用前需要轉(zhuǎn)換為RGBA32,這能從以下Time Profiler以及Allocation棧輕易證實(shí):

UploadTexture()中的needConversion圖略 )

Metal不支持RGB24涎嚼,交給GPU使用前需要轉(zhuǎn)換為RGBA32阱州,需要消耗CPU進(jìn)行一次BlitImage。

UploadMipPyramid()圖略 )

結(jié)論

通過Profile結(jié)果和源碼法梯,我們證實(shí)了:iOS設(shè)備中只有一塊物理內(nèi)存硬件苔货,主存地址和顯存地址在同一塊虛存地址空間中,虛存最終的確只有一份紋理內(nèi)容位于IOKit區(qū)域中立哑,而且該紋理內(nèi)容的確就是被GPU所用的紋理蒲赂。
在紋理上傳過程中,Unity先在堆內(nèi)存申請(qǐng)緩存刁憋,然后將紋理文件內(nèi)容讀進(jìn)緩存里滥嘴,然后調(diào)用圖形API將該該紋理內(nèi)容數(shù)據(jù)拷貝到IOKit虛存中,供GPU訪問至耻∪糁澹拷貝完成后緩存視乎情況從堆內(nèi)存釋放。
過程中尘颓,我們展示了在iOS中各種Profile工具的實(shí)際使用方法走触。
也介紹了一些基礎(chǔ)的內(nèi)存知識(shí)和概念。

下載實(shí)驗(yàn)工程及數(shù)據(jù)

見Github:MobileGFXMemoryTest

Android篇

打算未來才做Android的Profile實(shí)驗(yàn)和分析報(bào)告疤苹,但通過上面的分析看來互广,可以大膽預(yù)測(cè):

  1. Android設(shè)備也是基于ARM架構(gòu),想必各種Vendor的設(shè)備也是只有一塊物理內(nèi)存硬件;
  2. 上面的函數(shù)棧大多平臺(tái)無關(guān)惫皱,而且Vulkan和Metal是同一代的圖形框架像樊,所以Unity在Vulkan上的實(shí)現(xiàn)內(nèi)存流程應(yīng)該和Metal非常類似;
  3. 由于GLES是較老的框架旅敷,所以其內(nèi)存流程可能和Metal類似生棍,但要留意GLES具體情況,和其在驅(qū)動(dòng)內(nèi)部gralloc的使用情況媳谁,有沒有額外的拷貝

關(guān)鍵字

手機(jī)涂滴,GPU,顯存晴音,移動(dòng)設(shè)備柔纵,iPhone,iPad锤躁,iOS搁料,安卓,Android进苍,Mobile Device加缘,內(nèi)存鸭叙,共享內(nèi)存觉啊,物理內(nèi)存

引用

[1]ifixit - iPhone 6 Teardown
[2]Chipworks Disassembles Apple's A8 SoC
[3]Metal_(API)#Supported_GPUs
[4]Metal Best Practices Guide - Resource Options
[5]Metal - Resource Storage Mode
[6]MTLBuffer
[7]Triple Buffering
[8]iOS Memory Deep Dive
[9]Choosing a Resource Storage Mode in iOS and tvOS
[10]MTLBuffer makeTexture

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市沈贝,隨后出現(xiàn)的幾起案子杠人,更是在濱河造成了極大的恐慌,老刑警劉巖宋下,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嗡善,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡学歧,警方通過查閱死者的電腦和手機(jī)罩引,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來枝笨,“玉大人袁铐,你說我怎么就攤上這事『峄耄” “怎么了剔桨?”我有些...
    開封第一講書人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長徙融。 經(jīng)常有香客問我洒缀,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任树绩,我火速辦了婚禮萨脑,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘葱峡。我一直安慰自己砚哗,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開白布砰奕。 她就那樣靜靜地躺著蛛芥,像睡著了一般。 火紅的嫁衣襯著肌膚如雪军援。 梳的紋絲不亂的頭發(fā)上仅淑,一...
    開封第一講書人閱讀 49,071評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音胸哥,去河邊找鬼涯竟。 笑死,一個(gè)胖子當(dāng)著我的面吹牛空厌,可吹牛的內(nèi)容都是我干的庐船。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼嘲更,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼筐钟!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起赋朦,我...
    開封第一講書人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤篓冲,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后宠哄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體壹将,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年毛嫉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了诽俯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡承粤,死狀恐怖暴区,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情密任,我是刑警寧澤颜启,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站浪讳,受9級(jí)特大地震影響缰盏,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一口猜、第九天 我趴在偏房一處隱蔽的房頂上張望负溪。 院中可真熱鬧,春花似錦济炎、人聲如沸川抡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽崖堤。三九已至,卻和暖如春耐床,著一層夾襖步出監(jiān)牢的瞬間密幔,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來泰國打工撩轰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留胯甩,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓堪嫂,卻偏偏與公主長得像偎箫,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子皆串,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 開篇一張圖淹办,后面聽我編 1. 知識(shí)準(zhǔn)備 1.1 中央處理器(CPU) 中央處理器(CPU,Central Proc...
    He_Yu閱讀 46,998評(píng)論 7 115
  • 1愚战、通過CocoaPods安裝項(xiàng)目名稱項(xiàng)目信息 AFNetworking網(wǎng)絡(luò)請(qǐng)求組件 FMDB本地?cái)?shù)據(jù)庫組件 SD...
    陽明先生_x閱讀 15,968評(píng)論 3 119
  • 你是否知道娇唯, 我不知道啊 哈哈怎么樣這里 感覺不錯(cuò)~~~~
    Zoker閱讀 157評(píng)論 0 1
  • 半成品齐遵,為什么總是看得出筆觸呢 加了一只櫻桃 終于畫完了寂玲,手都快斷了 哎結(jié)構(gòu)沒畫好,線稿太重要
    百步穿楊啦閱讀 78評(píng)論 0 0
  • 晨露風(fēng)荷動(dòng)梗摇, 池鱗自在行拓哟。 竹泉清一色, 濯我世間纓伶授。
    水木清華Q閱讀 944評(píng)論 7 25