Alloy 0.16.3

Alloy 0.16.3

s1ddok维护。



Alloy 0.16.3

Alloy

Alloy是一组在Apple的Metal框架之上提供的实用工具和扩展,致力于使您的Swift GPU代码更简洁,并让您快速原型化您的管线。

虽然这个库没有引入任何新的范式或概念,以显著改变您处理Metal实现的方式,但它有一些可选的功能,如果您觉得它们和库作者一样有用,您可以将其整合到您的应用程序中:)

  • 覆盖vanilla Metal API的极小层
  • 无外部依赖项
  • 跨平台支持
  • 非常Swift化

使用示例

通过共享资源内存结合CoreGraphics和Metal的力量

好吧,让我看看发生了什么

首先,这个框架提供了一组实用工具,这些工具隐藏了大多数在您的Metal代码中的重复显式操作,同时又不限制任何灵活性。您可以将Alloy和vanilla Metal代码轻松混合。

Alloy引入的唯一一个新概念是MTLContext。内部,这被用来存储通常在您的应用程序中共享和注入的对象。

具体来说,这是

  • device: MTLDevice
  • commandQueue: MTLCommandQueue
  • standardLibrary: MTLLibrary?

内部,它还管理一个MTKTextureLoader和一个MTLLibraries的缓存,但这种逻辑应被视为私有。目前,MTLContext 不是线程安全的

MTLContext通常作为依赖项目注入到与Metal设备交互的任何对象中。

它可以为您做很多事情,以下是一些例子

轻松从CGImage创建纹理

let texture = context.texture(from: cgImage,
                              usage: [.shaderRead, .shaderWrite])

以同步/异步方式调度命令缓冲区

看看您如何使用Swift闭包将编码分组。

self.context.scheduleAndWait { buffer in
    buffer.compute { encoder in
      // compute command encoding logic
    }

    buffer.blit { encoder in
      // blit command encoding logic
    }
}

加载框架中函数的计算管线状态

let lib = context.shaderLibrary(for: Foo.self)
let computePipelineState = try? lib.computePipelineState(function: "brightness")

按值类型分配缓冲区

let buffer = context.buffer(for: InstanceUniforms.self,
                            count: 99,
                            options: .storageModeShared)

序列化和反序列化MTLTexture

let encoder = JSONEncoder()
let data = try encoder.encode(texture.codable())

let decoder = JSONDecoder()
let decodableTexture = try decoder.decode(MTLTextureCodableBox.self, from: data)
let decodedTexture = try decodableTexture.texture(device: self.context.device)

其他内容

  • 创建多样本渲染目标对
  • 创建纹理
  • 创建深度缓冲区
  • 创建深度/模板状态

其他合金特定类型

Alloy 中引入的其他类型包括:

  • MTLOffscreenRenderer:这是一个类,允许您创建简单的离屏渲染器,将内容绘制到任意的 MTLTextures 中。
  • ComputeCommand:这是一个 实验性类,可以对 Metal 核进行反射,并通过名称指定参数而不是索引。这是改进的对象。
  • BlendingMode:此类型包含 Alloy 内置的八种混合模式的枚举。您只需调用 setup(blending:) 函数即可轻松设置其中一个。
    let renderPipelineDescriptor = MTLRenderPipelineDescriptor()
    renderPipelineDescriptor.colorAttachments[0].setup(blending: .alpha)

MTLContext 最小使用示例

MTLContext 通常在类中注入,就像您通常将 MTLDevice 注入一样,您应该缓存上下文和所有重量级对象,以便稍后重用,即

import Alloy

public class BrightnessEncoder {
    public let context: MTLContext
    fileprivate let pipelineState: MTLComputePipelineState

    /**
     * This variable controls the brightness factor. Should be in range of -1.0...1.0
     */
    public var intensity: Float = 1.0

    public init(context: MTLContext) {
        self.context = context

        guard let lib = context.shaderLibrary(for: BrightnessEncoder.self),
              let state = try? lib.computePipelineState(function: "brightness")
        else { fatalError("Error during shader loading") }

        self.pipelineState = state
    }

    public func encode(input: MTLTexture,
                       in commandBuffer: MTLCommandBuffer) {
        commandBuffer.compute { encoder in
            encoder.set(textures: [input])
            encoder.set(self.intensity, at: 0)

            encoder.dispatch2d(state: self.pipelineState,
                               covering: input.size)
        }
    }

}

注意使用 Alloy 启动内核是多么简单,不再需要繁琐的线程组大小计算,也不再需要使用平衡的 .endEncoding() 调用多次初始化编码器。

然后在其他地方进行以下操作

context.scheduleAndWait { buffer in
    self.brightnessEncoder.intensity = sender.floatValue
    self.brightnessEncoder.encode(input: texture,
                                  in: buffer)

    // For Mac applications
    if case .managed = texture.storageMode {
        buffer.blit { encoder in
            encoder.synchronize(resource: texture)
        }
    }
}

采用这种方法,您可以轻松堆叠和构建您的 GPU 管道层,使用 Swift 闭包分组 blitcomputerender 命令编码,同时保持 full flexibility of Metal API。

安装

CocoaPods

CocoaPods 是 Cocoa 项目的依赖项管理器。有关用法和安装说明,请访问他们的网站。要使用 CocoaPods 将 Alloy 集成到您的 Xcode 项目中,请在 Podfile 中指定它。

# Optionally add version, i.e. '~> 0.9.0'
pod 'Alloy'

许可证

MIT