gpt4 book ai didi

metal - 如何将 MetalKit 纹理加载器与 Metal 堆一起使用?

转载 作者:行者123 更新时间:2023-12-01 13:59:04 31 4
gpt4 key购买 nike

我有一组 Metal 纹理作为纹理集存储在 Xcode Assets 目录中。我正在使用 MTKTextureLoader.newTexture(name:scaleFactor:bundle:options) 加载它们。

然后我使用 MTLArgumentEncoder 将所有纹理编码到 Metal 2 参数缓冲区中。

这很好用。然而,Metal 2 简介 WWDC 2017 session recommends combining argument buffers with resource heaps for even better performance ,我很想试试这个。根据Argument Buffer documentation ,不必在参数缓冲区中的每个纹理上调用 MTLRenderCommandEncoder.useResource,您只需在分配纹理的堆上调用 useHeap

但是,我还没有找到将 MTKTextureLoaderMTLHeap 一起使用的直接方法。它似乎没有从堆中分配纹理的加载选项。

我猜该方法是:

  • 使用 MTKTextureLoader 加载纹理
  • 对每个纹理的一组 MTLTextureDescriptor 对象进行逆向工程
  • 使用纹理描述符创建适当大小的MTLHeap
  • MTLHeap 中分配一组新的纹理
  • 使用某种方法复制纹理,可能是 replaceBytes 或者甚至是 MTLBlitCommandEncoder
  • 释放使用 MTKTextureLoader 加载的原始纹理

这似乎是一个相当冗长的方法,而且我还没有看到任何这样的例子,所以我想我应该先在这里问一下,以防我遗漏了一些明显的东西。

我是否应该放弃 MTKTextureLoader,并搜索一些关于从 Assets 目录加载纹理的前 MetalKit 艺术?

我正在使用 Swift,但很高兴接受 Objective-C 的答案。

最佳答案

好吧,我上面概述的方法似乎有效。正如预测的那样,它非常冗长。我很想知道是否有人有更优雅的东西。

enum MetalError: Error {
case anErrorOccured
}

extension MTLTexture {
var descriptor: MTLTextureDescriptor {
let descriptor = MTLTextureDescriptor()
descriptor.width = width
descriptor.height = height
descriptor.depth = depth
descriptor.textureType = textureType
descriptor.cpuCacheMode = cpuCacheMode
descriptor.storageMode = storageMode
descriptor.pixelFormat = pixelFormat
descriptor.arrayLength = arrayLength
descriptor.mipmapLevelCount = mipmapLevelCount
descriptor.sampleCount = sampleCount
descriptor.usage = usage
return descriptor
}

var size: MTLSize {
return MTLSize(width: width, height: height, depth: depth)
}
}

extension MTKTextureLoader {
func newHeap(withTexturesNamed names: [String], queue: MTLCommandQueue, scaleFactor: CGFloat, bundle: Bundle?, options: [MTKTextureLoader.Option : Any]?, onCompletion: (([MTLTexture]) -> Void)?) throws -> MTLHeap {
let device = queue.device
let sourceTextures = try names.map { name in
return try newTexture(name: name, scaleFactor: scaleFactor, bundle: bundle, options: options)
}
let storageMode: MTLStorageMode = .private
let descriptors: [MTLTextureDescriptor] = sourceTextures.map { source in
let desc = source.descriptor
desc.storageMode = storageMode
return desc
}
let sizeAligns = descriptors.map { device.heapTextureSizeAndAlign(descriptor: $0) }
let heapDescriptor = MTLHeapDescriptor()
heapDescriptor.size = sizeAligns.reduce(0) { $0 + $1.size }
heapDescriptor.cpuCacheMode = descriptors[0].cpuCacheMode
heapDescriptor.storageMode = storageMode
guard let heap = device.makeHeap(descriptor: heapDescriptor),
let buffer = queue.makeCommandBuffer(),
let blit = buffer.makeBlitCommandEncoder()
else {
throw MetalError.anErrorOccured
}
let destTextures = descriptors.map { descriptor in
return heap.makeTexture(descriptor: descriptor)
}
let origin = MTLOrigin()
zip(sourceTextures, destTextures).forEach {(source, dest) in
blit.copy(from: source, sourceSlice: 0, sourceLevel: 0, sourceOrigin: origin, sourceSize: source.size, to: dest, destinationSlice: 0, destinationLevel: 0, destinationOrigin: origin)
blit.generateMipmaps(for: dest)
}
blit.endEncoding()
buffer.addCompletedHandler { _ in
onCompletion?(destTextures)
}
buffer.commit()
return heap
}
}

关于metal - 如何将 MetalKit 纹理加载器与 Metal 堆一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49107687/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com