日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

[MetalKit]34-Working-with-memory-in-Metal内存管理

發布時間:2025/4/5 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [MetalKit]34-Working-with-memory-in-Metal内存管理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本系列文章是對 metalkit.org 上面MetalKit內容的全面翻譯和學習.

MetalKit系統文章目錄


今天我們關注一下使用GPU時的內存管理.Metal框架將內存資源定義為MTLBuffer對象,它是分配的無類型,無格式的內存(任何數據類型),MTLTexture對象則是分配的格式化內存來保存圖片數據.我們在本文中只關注緩沖器.

創建MTLBuffer對象時有三種選項:

  • makeBuffer(length:options:) 創建一個MTLBuffer對象并分配一塊新內存.
  • makeBuffer(bytes:length:options:) 從一片已經存在的區域復制數據到一塊新分配的內存.
  • makeBuffer(bytesNoCopy:length:options:deallocator:) 重用一塊已經存在的內存.

讓我們創建一組緩沖器,看看數據是如何被傳遞到GPU的,及如何回傳給CPU.我們首先創建一塊緩沖器給輸入和輸出數據,并給它們初始化一些值:

let count = 1500 var myVector = [Float](repeating: 0, count: count) var length = count * MemoryLayout< Float >.stride var outBuffer = device.makeBuffer(bytes: myVector, length: length, options: []) for (index, value) in myVector.enumerated() { myVector[index] = Float(index) } var inBuffer = device.makeBuffer(bytes: myVector, length: length, options: []) 復制代碼

新的MemoryLayout< Type >.stride語法在Swift 3被引入,來替代老的strideof(Type)函數.同時,因為內存排列的原因我們用.stride替代了.size.stride是指針增長時移動的字節數.下一步是把我們緩沖器告訴命令編碼器:

encoder.setBuffer(inBuffer, offset: 0, at: 0) encoder.setBuffer(outBuffer, offset: 0, at: 1) 復制代碼

注意: <Metal最佳實踐指南>指出當我們的數據小于4KB(例如一個千位的浮點數)時就避免創建緩沖器.在本例中我們應該使用setBytes()函數來代替創建緩沖器.

最后一步是讀取GPU通過contents() 函數返回的數據,綁定內存數據到我們的輸出緩沖器上:

let result = outBuffer.contents().bindMemory(to: Float.self, capacity: count) var data = [Float](repeating:0, count: count) for i in 0 ..< count { data[i] = result[i] } 復制代碼

Metal資源必須被配置好,以便快速內存訪問和驅動器性能優化.資源的儲存模式允許我們定義緩沖器和紋理的儲存位置和訪問權限.如果你再看一眼上面我們創建緩沖器的地方,我們使用了默認([])的儲存模式.

所有的iOS和tvOS設備支持unified memory model統一內存模型,它可以讓CPU和GPU共享系統內存,而macOS設備支持discrete memory model離散內存模型即GPU擁有自己的內存.在iOS和tvOS中,Shared模式(MTLStorageModeShared)定義了系統內存可以被CPU和GPU訪問,而Private模式(MTLStorageModePrivate)定義系統內存只能被GPU訪問.Shared模式是所有三種操作系統中的默認儲存模式.

除了這兩種儲存模式外,macOS還有一種Managed模式(MTLStorageModeManaged),它為一種資源定義了一對同步內存,一個副本在系統內存中,另一個在視頻內存中來獲得更快的CPU和GPU本地訪問.

現在讓我們看看當我們將數據緩沖器發送給GPU時,GPU上面發生了什么.下面是個典型的頂點著色器例子:

vertex Vertices vertex_func(const device Vertices *vertices [[buffer(0)]], constant Uniforms &uniforms [[buffer(1)]], uint vid [[vertex_id]]) {... } 復制代碼

Metal Shading Language實現了地址空間修飾詞來指定當函數變量或參數分配時的內存區域:

  • device - 指緩沖器內存對象,從設備內存池中分配,既可讀又可寫除非前面有const關鍵詞就是只讀的.
  • constant - 指緩沖器內存對象,從設備內存池中分配,但是是read-only只讀的.程序作用域內的變量必須被聲明為常量地址空間,并在聲明語句中被初始化.常量地址空間為多個實例在執行圖形或內核函數時訪問緩沖器中的同一塊位置的做了優化.
  • threadgroup - 僅用來分配內核函數中使用的變量,它們是為每個執行內核的線程組分配的,被線程組內的所有線程共享,只在執行內核的線程組的生命周期內才存在.
  • thread - 指每個線程的內存地址空間.分配在這個地址空間的變量對其它線程是不可見的.在圖形或內核函數中聲明的變量是分配在線程地址空間的.

作為獎勵,讓我們也看一下在Swift 3中另一種訪問內存位置的方法.這段代碼是從前面的文章The Model I/O framework中摘抄的,所以我們就不再講解體素的細節了.只要想著我們需要遍歷一個數組來獲取值:

let url = Bundle.main.url(forResource: "teapot", withExtension: "obj") let asset = MDLAsset(url: url) let voxelArray = MDLVoxelArray(asset: asset, divisions: 10, patchRadius: 0) if let data = voxelArray.voxelIndices() {data.withUnsafeBytes { (voxels: UnsafePointer<MDLVoxelIndex>) -> Void inlet count = data.count / MemoryLayout<MDLVoxelIndex>.sizelet position = voxelArray.spatialLocation(ofIndex: voxels.pointee)print(position)} } 復制代碼

在本例中,MDLVoxelArray對象有了個名為spatialLocation()的函數,它讓我們用一個MDLVoxelIndex類型的UnsafePointer指針來遍歷數組,并通過每個位置的pointee來訪問數據.在本例中,我們只打印出地址中的第一個值,但一個簡單的循環可以讓我們得到所有的數,像這樣:

var voxelIndex = voxels for _ in 0..<count {let position = voxelArray.spatialLocation(ofIndex: voxelIndex.pointee)print(position)voxelIndex = voxelIndex.successor() } 復制代碼

源代碼source code已發布在Github上.

下次見!

總結

以上是生活随笔為你收集整理的[MetalKit]34-Working-with-memory-in-Metal内存管理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。