Metal Programming Guide


讀蘋果文檔時的筆記,給自己看。

primary goal of Metal is to minimize the CPU overhead incurred by executing GPU workloads.

用在兩個方面:

  • graphics
  • data-parallel computation

Metal App 不能在后台運行,否則會被終止。

Command Organization and Execution Model

  • MTLDevice 是對 GPU 的建模。
  • command queue,由若干 command buffer 組成的隊列,並負責這些 command buffer 的執行順序。
  • command buffer,包含 encoded commands (要在設備上執行的指令)。
  • command encoder,把命令加到 command buffer 中。

Transient and Non-transient Objects in Metal

Command buffer 和 command encoder 是輕量級的,設計為單次使用。
下面這些的創建是比較消耗資源的,應該復用。

  • Command queues
  • Data buffers
  • Textures
  • Sampler states
  • Libraries
  • Compute states
  • Render pipeline states
  • Depth/stencil states

Registering Handler Blocks for Command Buffer Execution

block 中的方法可能在任意線程調用,並且不應該是耗時的。

  • addScheduledHandler:
  • waitUntilScheduled:
  • addCompletedHandler:
  • waitUntilCompleted

Resource Objects: Buffers and Textures

MTLBuffer 有兩個類型。

  • MTLBuffer: 無格式 (unformatted) 的內存,可以表示任意類型數據。
  • MTLTexture: 有格式 (formatted) 的圖像數據。

Buffers Are Typeless Allocations of Memory

  • contents 方法返回 buffer 的 CPU 內存地址。
  • newTextureWithDescriptor:offset:bytesPerRow: 方法創建 texture 對象,指向 buffer 的數據。

Textures Are Formatted Image Data

可以有下面的結構

  • A 1D, 2D, or 3D image
  • An array of 1D or 2D images
  • A cube of six 2D images

Creating a Texture Object

  • newTextureWithDescriptor:
    MTLDevice調用,創建 MTLTexture 對象,分配了存儲空間。使用 MTLTextureDescriptor 來描述紋理的性質。
  • newTextureViewWithPixelFormat:
    MTLTexture 調用,返回 MTLTexture 對象,和原來的紋理共享內存地址。新的紋理用新的像素格式來解釋原有的紋理數據。
  • newTextureWithDescriptor:offset:bytesPerRow:
    MTLBuffer 調用,返回 MTLTexture 對象,和原來的 buffer 共享內存地址。

使用 Texture Descriptor 來創建紋理對象

MTLTextureDescriptor 定義了紋理的性質,只是用來創建紋理對象。在創建好紋理對象之后,對它的修改不會有任何影響。

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

Copying Image Data to and from a Texture

  1. 把數據寫入紋理
    • replaceRegion:mipmapLevel:slice:withBytes:bytesPerRow:bytesPerImage:
    • replaceRegion:mipmapLevel:withBytes:bytesPerRow:
  2. 把數據從紋理讀出來
    • getBytes:bytesPerRow:bytesPerImage:fromRegion:mipmapLevel:slice:
    • getBytes:bytesPerRow:fromRegion:mipmapLevel:

例子如下:

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

Pixel Formats for Textures

有三種像素類型:

  1. Ordinary formats
  2. Packed formats
  3. Compressed formats

Creating a Sampler States Object for Texture Lookup

  1. 創建 MTLSamplerDescriptor 對象
  2. 設置對象的性質
  3. 創建 MTLSamplerState 對象。

MTLSamplerState 對象只是用來創建 MTLSamplerState 對象。創建完之后,對它的修改不會影響已經創建好的 MTLSamplerState 對象。

// create MTLSamplerDescriptor
MTLSamplerDescriptor *desc = [[MTLSamplerDescriptor alloc] init];
desc.minFilter = MTLSamplerMinMagFilterLinear;
desc.magFilter = MTLSamplerMinMagFilterLinear;
desc.sAddressMode = MTLSamplerAddressModeRepeat;
desc.tAddressMode = MTLSamplerAddressModeRepeat;
//  all properties below have default values
desc.mipFilter        = MTLSamplerMipFilterNotMipmapped;
desc.maxAnisotropy    = 1U;
desc.normalizedCoords = YES;
desc.lodMinClamp      = 0.0f;
desc.lodMaxClamp      = FLT_MAX;
// create MTLSamplerState
id <MTLSamplerState> sampler = [device newSamplerStateWithDescriptor:desc];

Maintaining Coherency Between CPU and GPU Memory

CPU 和 GPU 都可以訪問 MTLResource 對象。
GPU 只能記錄在 MTLCommandBuffercommit 方法調用之前,CPU 對 MTLResource 的改動。
CPU 只有在 GPU 完成 MTLCommandBuffer 中的指令之后,才可以看到 GPU 對 MTLResource 的改動。

Functions and Libraries

MTLFunction Represents a Shader or Compute Function

只有被 vertexfragmentkernel 修飾的函數才可以表示為 MTLFunction

A Library Is a Repository of Functions

Library 中的 MTLFunction 可以有兩個來源:

  1. 在 build 階段被編譯好的二進制 Metal shading language code
  2. 包含 Metal shading language 源代碼的字符串,在運行時被編譯

Creating a Library from Compiled Code

可以提高效率,不必在運行時編譯源代碼。
可以通過以下方法來獲取 MTLLibrary

  1. newDefaultLibrary
  2. newLibraryWithFile:error:
  3. newLibraryWithData:error:

Creating a Library from Source Code

  1. newLibraryWithSource:options:error: 同步方法
  2. newLibraryWithSource:options:completionHandler: 異步方法

Graphics Rendering: Render Command Encoder

Metal Graphics Rendering Pipeline

Creating a Render Pass Descriptor

MTLRenderPassDescriptor 表示 encoded rendering commands 的目的地 (destination)。MTLRenderPassDescriptor 的屬性可以包括至多 4 個顏色的 attachments,一個像素深度數據的 attachment,一個像素 stencil 數據的 attachment。

Load and Store Actions

指定了在 rendering pass 的起始和結束時的動作。
loadAction 包括:

  1. MTLLoadActionClear 為每一個像素寫入指定的值。
  2. MTLLoadActionLoad 保存已有的值
  3. MTLLoadActionDontCare 在起始階段可以有任意值,性能最高。

storeAction 包括

  1. MTLStoreActionStore 保存最后的像素值,color attachments 的默認值
  2. MTLStoreActionMultisampleResolve
  3. MTLStoreActionDontCare 會提高性能。depth and stencil attachments 的默認值。

一個例子如下:

MTLTextureDescriptor *colorTexDesc = [MTLTextureDescriptor
           texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm
           width:IMAGE_WIDTH height:IMAGE_HEIGHT mipmapped:NO];
id <MTLTexture> colorTex = [device newTextureWithDescriptor:colorTexDesc];

MTLTextureDescriptor *depthTexDesc = [MTLTextureDescriptor
           texture2DDescriptorWithPixelFormat:MTLPixelFormatDepth32Float
           width:IMAGE_WIDTH height:IMAGE_HEIGHT mipmapped:NO];
id <MTLTexture> depthTex = [device newTextureWithDescriptor:depthTexDesc];

MTLRenderPassDescriptor *renderPassDesc = [MTLRenderPassDescriptor renderPassDescriptor];
renderPassDesc.colorAttachments[0].texture = colorTex;
renderPassDesc.colorAttachments[0].loadAction = MTLLoadActionClear;
renderPassDesc.colorAttachments[0].storeAction = MTLStoreActionStore;
renderPassDesc.colorAttachments[0].clearColor = MTLClearColorMake(0.0,1.0,0.0,1.0);

renderPassDesc.depthAttachment.texture = depthTex;
renderPassDesc.depthAttachment.loadAction = MTLLoadActionClear;
renderPassDesc.depthAttachment.storeAction = MTLStoreActionStore;
renderPassDesc.depthAttachment.clearDepth = 1.0;

Using the Render Pass Descriptor to Create a Render Command Encoder

id <MTLRenderCommandEncoder> renderCE = [commandBuffer
                    renderCommandEncoderWithDescriptor:renderPassDesc];

Displaying Rendered Content with Core Animation

利用 CAMetalLayer

Creating a Render Pipeline State

MTLRenderPipelineState 對象生命周期很長,應該緩存起來復用。
MTLRenderPipelineState 對象是不可變的。先創建一個 MTLRenderPipelineDescriptor,設置好性質,然后再創建 MTLRenderPipelineState

例子如下:

MTLRenderPipelineDescriptor *renderPipelineDesc =
                             [[MTLRenderPipelineDescriptor alloc] init];
renderPipelineDesc.vertexFunction = vertFunc;
renderPipelineDesc.fragmentFunction = fragFunc;
renderPipelineDesc.colorAttachments[0].pixelFormat = MTLPixelFormatRGBA8Unorm;

// Create MTLRenderPipelineState from MTLRenderPipelineDescriptor
NSError *errors = nil;
id <MTLRenderPipelineState> pipeline = [device
         newRenderPipelineStateWithDescriptor:renderPipelineDesc error:&errors];
assert(pipeline && !errors);

// Set the pipeline state for MTLRenderCommandEncoder
[renderCE setRenderPipelineState:pipeline];

Specifying Resources for a Render Command Encoder

調用 setVertex* 以及 setVertex* 方法。

Drawing Geometric Primitives

調用 draw* 方法。

Ending a Rendering Pass

調用 endEncoding 方法


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM