原文https://developer.apple.com/documentation/metal/fundamental_lessons/basic_buffers
基礎(chǔ)緩沖區(qū)
展示如何使用頂點(diǎn)緩沖區(qū)管理數(shù)以百計(jì)的頂點(diǎn)數(shù)據(jù).
示例代碼下載
概覽
在你好,三角形示例中,你將要通過(guò)Metal API 學(xué)習(xí)如何渲染基本的幾何體.
在本示例中, 你將要學(xué)習(xí)如何使用 頂點(diǎn)緩沖區(qū)[vertex buffer] 改善 你的渲染效率. 特別是 你將要學(xué)習(xí)如何使用頂點(diǎn)緩沖區(qū) 去存儲(chǔ)和加載頂點(diǎn)數(shù)據(jù)為 多正方形.
管理大量的頂點(diǎn)數(shù)據(jù)
在你好,三角形中,該示例 渲染了 3個(gè)頂點(diǎn) 32 個(gè)字節(jié), 一共 96字節(jié) 的頂點(diǎn)數(shù)據(jù) 通過(guò)調(diào)用 setVertexBytes:length:atIndex:
方法 發(fā)送給頂點(diǎn)著色器, 該方法 分配 小量?jī)?nèi)存 , 容易達(dá)到 GPU , 和分配 每一幀 需要 明顯的性能消耗.
不像你好,三角形示例中,該示例渲染 3600個(gè)頂點(diǎn) 每個(gè)頂點(diǎn)為32個(gè)字節(jié), 總共115,200字節(jié)的頂點(diǎn)數(shù)據(jù).大量的頂點(diǎn)數(shù)據(jù)需要高效的管理. 實(shí)際上, Metal 不允許使用 setVertexBytes:length:atIndex:
頂點(diǎn)數(shù)據(jù) 超出4KB,
重要的是 頂點(diǎn)數(shù)據(jù) 應(yīng)該不實(shí)際分配和復(fù)制每一幀.
典型的, Metal app 或者 游戲 繪制 模型數(shù)以千計(jì)的頂點(diǎn)數(shù)據(jù), 多頂點(diǎn)屬性. 消耗MB的內(nèi)存, 這些app 或者 游戲 縮放很好,管理高效.
Metal 提供指定的數(shù)據(jù)容器 通過(guò) MTLBuffer
對(duì)象 展示. 這些 buffer 是 GPU 內(nèi)存 分配 存儲(chǔ) 多類(lèi)型的自定義數(shù)據(jù). 盡管他們使用頂點(diǎn)數(shù)據(jù).該示例分配大量的頂點(diǎn)一次,復(fù)制到MTLBuffer
對(duì)象 和重用頂點(diǎn)數(shù)據(jù) 在每一幀.
分配,創(chuàng)建和復(fù)制頂點(diǎn)數(shù)據(jù)
在Objective-C
中, 字節(jié)緩沖區(qū) 通過(guò)NSData
或者 NSMutableData
對(duì)象封裝. 這些對(duì)象 安全高效.
AAPLVertex
數(shù)據(jù)類(lèi)型 是用于每一個(gè)頂點(diǎn)在示例范圍中, 每一個(gè)正方形 由6個(gè)頂點(diǎn)值組成,(一個(gè)正方形需要兩個(gè)三角形), 30x20 正方形 大概 3600 個(gè)頂點(diǎn) 發(fā)生 115,220 字節(jié)內(nèi)存, 這些大量的 分配 示例的頂點(diǎn)數(shù)據(jù).
static const AAPLVertex quadVertices[] =
{
// Pixel Positions, RGBA colors
{ { -20, 20 }, { 1, 0, 0, 1 } },
{ { 20, 20 }, { 0, 0, 1, 1 } },
{ { -20, -20 }, { 0, 1, 0, 1 } },
{ { 20, -20 }, { 1, 0, 0, 1 } },
{ { -20, -20 }, { 0, 1, 0, 1 } },
{ { 20, 20 }, { 0, 0, 1, 1 } },
};
const NSUInteger NUM_COLUMNS = 30;
const NSUInteger NUM_ROWS = 20;
const NSUInteger NUM_VERTICES_PER_QUAD = sizeof(quadVertices) / sizeof(AAPLVertex);
const float QUAD_SPACING = 50.0;
NSUInteger dataSize = sizeof(quadVertices) * NUM_COLUMNS * NUM_ROWS;
NSMutableData *vertexData = [[NSMutableData alloc] initWithLength:dataSize];
Metal app或者游戲 從模型文件中加載頂點(diǎn)數(shù)據(jù). 模型加載代碼的復(fù)雜度取決于模型,最終的頂點(diǎn)數(shù)據(jù) 同樣也存儲(chǔ)在 字節(jié)緩沖區(qū), 處理成Metal code.
為了避免 介紹 模型載入代碼,本示例 generateVertexData
方法 創(chuàng)建簡(jiǎn)單的頂點(diǎn)數(shù)據(jù)在運(yùn)行時(shí).
NSData
和MTLBuffer
對(duì)象 存儲(chǔ)自定義數(shù)據(jù), 意味著 你的APP 是一個(gè) 定義和中斷 這些數(shù)據(jù)正確 在 讀和寫(xiě)的操作, 在本案例中 頂點(diǎn)數(shù)據(jù) 只讀 和 內(nèi)存分布 定義 AAPLVertex
數(shù)據(jù)類(lèi)型 vertexShader
頂點(diǎn)著色器 要求.
vertex RasterizerData
vertexShader(uint vertexID [[ vertex_id ]],
constant AAPLVertex *vertices [[ buffer(AAPLVertexInputIndexVertices) ]],
constant vector_uint2 *viewportSizePointer [[ buffer(AAPLVertexInputIndexViewportSize) ]])
基本的 ,NSData
和MTLBuffer
對(duì)象 極其相似. 然而 MTLBuffer
對(duì)象是指定包含 GPU , 開(kāi)啟 圖形渲染管線去讀取頂點(diǎn)數(shù)據(jù)從緩沖區(qū)中.
NSData *vertexData = [AAPLRenderer generateVertexData];
// Create our vertex buffer, allocating storage that can be read directly the GPU
_vertexBuffer = [_device newBufferWithLength:vertexData.length
options:MTLResourceStorageModeShared];
// Copy our vertex array into _vertexBuffer by accessing a pointer via the 'contents' property
memcpy(_vertexBuffer.contents, vertexData.bytes, vertexData.length);
第一, newBufferWithLength:options:
方法 創(chuàng)建新的 MTLBuffer
對(duì)象 中心字節(jié)大小, 中心訪問(wèn)選項(xiàng). 頂點(diǎn)數(shù)據(jù)發(fā)生 115,200字節(jié)內(nèi)存 (vertexData.length
) 這寫(xiě) CPU 和 讀取GPU (MTLResourceStorageModeShared
)
第二 memcpy()
函數(shù)服裝頂點(diǎn)數(shù)據(jù) 從 數(shù)據(jù)源NSData 對(duì)象 目標(biāo) MTLBuffer
對(duì)象.
_vertexBuffer.contents
查詢 返回CPU 指針 到 buffer 內(nèi)存.
頂點(diǎn)數(shù)據(jù) 復(fù)制 源數(shù)據(jù)的指針(vertexData.bytes
) 和 指定大量的數(shù)據(jù) 復(fù)制 (vertexData.length
) .
發(fā)送和繪制頂點(diǎn)數(shù)據(jù)
因?yàn)?示例中的頂點(diǎn)數(shù)據(jù) 現(xiàn)在存儲(chǔ)在MTLBuffer
對(duì)象中, setVertexBytes:length:atIndex:
方法能夠 不再 調(diào)用.
使用 VertexBuffer:offset:atIndex:
方法代替.
該方法 用頂點(diǎn)buffer 作為參數(shù), 字節(jié)偏移 頂點(diǎn)數(shù)據(jù) 在buffer 以及 映射的索引 頂點(diǎn)函數(shù)中 buffer的索引.
注意:
使用MTLBuffer
對(duì)象 作為 頂點(diǎn)函數(shù)參數(shù) 不保護(hù)APP 或者游戲 使用setVertexBytes:length:atIndex:
方法 設(shè)置 其他參數(shù) 數(shù)據(jù).
事實(shí)上, 該示例使用viewportSizePointer
參數(shù) 已經(jīng)在 你好,三角形 介紹過(guò)了.
最后,所有頂點(diǎn) 被繪制 調(diào)用 開(kāi)始 第一個(gè)頂點(diǎn) array(0) 到 (_numVertices).
[renderEncoder setVertexBuffer:_vertexBuffer
offset:0
atIndex:AAPLVertexInputIndexVertices];
[renderEncoder setVertexBytes:&_viewportSize
length:sizeof(_viewportSize)
atIndex:AAPLVertexInputIndexViewportSize];
// Draw the vertices of our quads
[renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle
vertexStart:0
vertexCount:_numVertices];
接下來(lái)
本示例,你學(xué)習(xí) 如何使用頂點(diǎn)緩沖區(qū)改善你的渲染效率.
在基本紋理示例中,你將要學(xué)習(xí)如何加載圖片數(shù)據(jù)和紋理貼圖一個(gè)正方形.