mcpField
M
metal-gpu

metal-gpu

github.com/ios-agent开发12312 次安装34 周前更新
代码仓库

关于 metal-gpu

此技能为编写 Metal GPU 代码提供模式、API 提示和性能建议,面向使用 Metal 与 Swift 开发 GPU 渲染或计算的开发者。内容覆盖命令流水线、MSL 着色器及 Apple GPU 优化。

主要功能

  1. 01Metal 命令流水线模式
  2. 02编写 MSL 顶点、片元和计算着色器
  3. 03配置 Swift 渲染与计算管线
  4. 04管理资源存储模式和缓冲区
  5. 05提供性能优化与常见问题提示
  6. 06涵盖 Metal 4 API 变化

适用场景

  1. 01搭建 Metal 渲染管线
  2. 02编写 GPU 计算内核
  3. 03减少渲染循环中的资源分配
  4. 04排查编码器、缓冲区索引和像素格式问题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/ios-agent/iosagent.dev --skill metal-gpu

安装后在 Claude Code 中输入/metal-gpu确认已加载。

附带文件references/metal-api-guide.md

详细介绍

Metal GPU 代码技能

编写生产级 Metal 代码,遵循正确模式,实现最佳性能,并提供清晰说明。

何时阅读参考资料

如需了解详细的 API 结构、Metal 4 特性和 Apple Silicon 优化模式,请阅读:

/mnt/skills/user/metal-gpu/references/metal-api-guide.md

核心原则

  1. 始终从设备开始:MTLCreateSystemDefaultDevice() —— 每个 Metal 工作流都从这里开始
  2. 命令模式:Device → Command Queue → Command Buffer → Command Encoder → Commit
  3. 着色器使用 MSL(Metal Shading Language):基于 C++14,并包含 Metal 专属类型和属性
  4. 资源管理很重要:使用合适的存储模式,避免不必要的拷贝
  5. 在渲染循环中使用三重缓冲,让 CPU 和 GPU 并行工作

快速参考:Metal 命令管线

MTLDevice
  └─ makeCommandQueue() → MTLCommandQueue
       └─ makeCommandBuffer() → MTLCommandBuffer
            ├─ makeRenderCommandEncoder(descriptor:) → MTLRenderCommandEncoder
            ├─ makeComputeCommandEncoder() → MTLComputeCommandEncoder
            └─ makeBlitCommandEncoder() → MTLBlitCommandEncoder

编写着色器(MSL)

使用 Metal Shading Language。始终包含:

  • #include <metal_stdlib> 和 using namespace metal;
  • 正确的属性限定符:[[vertex_id]]、[[position]]、[[stage_in]]、[[buffer(n)]]、[[texture(n)]]
  • 正确的地址空间限定符:device、constant、threadgroup、thread
顶点着色器模式
#include <metal_stdlib>
using namespace metal;

struct VertexIn {
    float3 position [[attribute(0)]];
    float3 normal   [[attribute(1)]];
    float2 texCoord [[attribute(2)]];
};

struct VertexOut {
    float4 position [[position]];
    float3 normal;
    float2 texCoord;
};

vertex VertexOut vertex_main(VertexIn in [[stage_in]],
                             constant float4x4 &mvp [[buffer(1)]]) {
    VertexOut out;
    out.position = mvp * float4(in.position, 1.0);
    out.normal = in.normal;
    out.texCoord = in.texCoord;
    return out;
}
片段着色器模式
fragment float4 fragment_main(VertexOut in [[stage_in]],
                              texture2d<float> albedo [[texture(0)]],
                              sampler texSampler [[sampler(0)]]) {
    float4 color = albedo.sample(texSampler, in.texCoord);
    return color;
}
计算内核模式
kernel void compute_main(device float *input  [[buffer(0)]],
                         device float *output [[buffer(1)]],
                         uint id [[thread_position_in_grid]]) {
    output[id] = input[id] * 2.0;
}

Swift 端设置模式

渲染管线设置
let device = MTLCreateSystemDefaultDevice()!
let commandQueue = device.makeCommandQueue()!

// Load shaders
let library = device.makeDefaultLibrary()!
let vertexFunction = library.makeFunction(name: "vertex_main")
let fragmentFunction = library.makeFunction(name: "fragment_main")

// Pipeline descriptor
let pipelineDescriptor = MTLRenderPipelineDescriptor()
pipelineDescriptor.vertexFunction = vertexFunction
pipelineDescriptor.fragmentFunction = fragmentFunction
pipelineDescriptor.colorAttachments[0].pixelFormat = .bgra8Unorm

// Vertex descriptor
let vertexDescriptor = MTLVertexDescriptor()
vertexDescriptor.attributes[0].format = .float3  // position
vertexDescriptor.attributes[0].offset = 0
vertexDescriptor.attributes[0].bufferIndex = 0
vertexDescriptor.layouts[0].stride = MemoryLayout<SIMD3<Float>>.stride
pipelineDescriptor.vertexDescriptor = vertexDescriptor

let pipelineState = try! device.makeRenderPipelineState(descriptor: pipelineDescriptor)
计算管线设置
let computeFunction = library.makeFunction(name: "compute_main")!
let computePipeline = try! device.makeComputePipelineState(function: computeFunction)

let commandBuffer = commandQueue.makeCommandBuffer()!
let encoder = commandBuffer.makeComputeCommandEncoder()!
encoder.setComputePipelineState(computePipeline)
encoder.setBuffer(inputBuffer, offset: 0, index: 0)
encoder.setBuffer(outputBuffer, offset: 0, index: 1)

let gridSize = MTLSize(width: elementCount, height: 1, depth: 1)
let threadGroupSize = MTLSize(
    width: min(computePipeline.maxTotalThreadsPerThreadgroup, elementCount),
    height: 1, depth: 1
)
encoder.dispatchThreads(gridSize, threadsPerThreadgroup: threadGroupSize)
encoder.endEncoding()
commandBuffer.commit()
MetalKit 视图渲染
import MetalKit

class Renderer: NSObject, MTKViewDelegate {
    let device: MTLDevice
    let commandQueue: MTLCommandQueue
    let pipelineState: MTLRenderPipelineState

    func draw(in view: MTKView) {
        guard let drawable = view.currentDrawable,
              let descriptor = view.currentRenderPassDescriptor else { return }

        let commandBuffer = commandQueue.makeCommandBuffer()!
        let encoder = commandBuffer.makeRenderCommandEncoder(descriptor: descriptor)!

        encoder.setRenderPipelineState(pipelineState)
        // Set buffers, draw primitives...
        encoder.drawPrimitives(type: .triangle, vertexStart: 0, vertexCount: 3)

        encoder.endEncoding()
        commandBuffer.present(drawable)
        commandBuffer.commit()
    }
}

性能最佳实践

  1. 存储模式:在 Apple Silicon 上使用 .shared(统一内存),GPU 专用数据使用 .private,Intel Mac 上使用 .managed
  2. 三重缓冲:使用信号量轮换 3 个缓冲区,避免 CPU/GPU 停顿
  3. 避免逐帧分配:重用缓冲区和命令编码器
  4. 尽可能使用 dispatchThreads,而不是 dispatchThreadgroups(Apple Silicon)
  5. 在 Apple GPU 上优先采用基于瓦片的延迟渲染模式——使用 imageblocks 和瓦片着色器
  6. 提前编译管线:创建管线的开销很大,应在加载时完成
  7. 使用 Xcode 中的 Metal GPU 帧捕获进行性能分析和调试

应避免的常见错误

  • 提交前忘记调用 encoder.endEncoding()
  • Swift 和 MSL 之间的缓冲区索引不匹配
  • 渲染目标使用了错误的像素格式
  • 未处理 Metal API 可选调用返回的 nil
  • 阻塞主线程等待 GPU 完成——改用 addCompletedHandler
  • 使用 [[stage_in]] 时忘记设置顶点描述符

Metal 4 说明

Metal 4 引入了现代化的核心 API。主要变化:

  • 新的编译 API,可更精细地控制着色器编译
  • 更新了命令编码模式
  • 完整的 Metal 4 API 结构请参阅 references/metal-api-guide.md

框架生态系统

框架用途
Metal直接访问 GPU、着色器、管线
MetalKit视图管理、纹理加载、模型 I/O
MetalFX性能优化用的超分辨率(时间/空间)
Metal Performance Shaders优化的计算与图像处理内核
Compositor ServicesvisionOS 立体渲染
RealityKit高级 3D 渲染(底层使用 Metal)

评论

支持 Markdown