我有一组Metal纹理,它们作为纹理集存储在Xcode Assets目录中。我使用MTKTextureLoader.newTexture(name:scaleFactor:bundle:options)
加载这些内容。
然后我使用MTLArgumentEncoder
将所有纹理编码为Metal 2参数缓冲区。
这很有效。然而,介绍金属2 WWDC 2017会议non-overlapping occurrences,我非常渴望尝试这一点。根据{{3}},您不必在参数缓冲区中的每个纹理上调用MTLRenderCommandEncoder.useResource
,而只需在堆上调用纹理分配的useHeap
。
但是,我还没有找到一种直接使用MTKTextureLoader
和MTLHeap
的方式。它似乎没有一个加载选项来从堆中分配纹理。
我猜测方法是:
MTKTextureLoader
MTLTextureDescriptor
个对象MTLHeap
MTLHeap
replaceBytes
,甚至是MTLBlitCommandEncoder
MTKTextureLoader
这似乎是一个相当冗长的方法,而且我没有看到任何这方面的例子,所以我想我先问这里,以防我错过了一些明显的东西。
我应该放弃MTKTextureLoader
,并在从资产目录中加载纹理时搜索一些前MetalKit艺术品吗?
我使用Swift,但很高兴接受Objective-C答案。
答案 0 :(得分:0)
嗯,我上面概述的方法似乎有效。正如预测的那样,它非常啰嗦。我很想知道是否有人有更优雅的东西。
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
}
}