为什么我无法读取那些MTLTexture像素?

时间:2017-01-10 20:29:12

标签: swift metal

我试图通过这种方式获得MTLTexture的像素:

let pixelCount = compareTexture.width * compareTexture.height

let region = MTLRegionMake2D(0, 0, compareTexture.width, compareTexture.height)  

var textureComponentsArray = Array<float4>(repeating: float4(0), count: pixelCount)

textureComponentsArray.withUnsafeMutableBytes {
   compareTexture.getBytes($0.baseAddress!, bytesPerRow: (MemoryLayout<float4>.size * compareTexture.width), from: region, mipmapLevel: 0)
}

print(textureComponentsArray.first!)

不幸的是,大多数元素都是NaN或等于我初始化textureComponentsArray的值。例如,此代码打印:

float4(nan, nan, nan, nan)

我在macOS上,我的MTLTexture有这些属性:

let textureDescriptor = MTLTextureDescriptor()
textureDescriptor.width = imageTexture.width
textureDescriptor.height = imageTexture.height
textureDescriptor.pixelFormat = imageTexture.pixelFormat
textureDescriptor.resourceOptions = .storageModeManaged
textureDescriptor.storageMode = .managed
textureDescriptor.usage = [.renderTarget, .shaderRead, .shaderWrite]

我确实使用托管存储模式,因此数据应该可供CPU使用,我不明白为什么它不起作用。

谢谢。

编辑:
我正在尝试使用:

blitCommandEncoder.synchronize(resource: compareTexture)

我确实等待命令缓冲区完成但仍有问题。

1 个答案:

答案 0 :(得分:0)

我需要针对iOS的此问题的答案。我要把为我的需要编写的扩展名留在这里。

import Metal

extension MTLTexture {
  func getPixels<T> (_ region: MTLRegion? = nil, mipmapLevel: Int = 0) -> UnsafeMutablePointer<T> {
    let fromRegion  = region ?? MTLRegionMake2D(0, 0, self.width, self.height)
    let width       = fromRegion.size.width
    let height      = fromRegion.size.height
    let bytesPerRow = MemoryLayout<T>.stride * width
    let data        = UnsafeMutablePointer<T>.allocate(capacity: bytesPerRow * height)

    self.getBytes(data, bytesPerRow: bytesPerRow, from: fromRegion, mipmapLevel: mipmapLevel)
    return data
  }
}

您可以简单地调用该函数。但是请记住,您有责任重新分配用于数据对象的内存。

如果像素也采用不同的格式,则可以读取它们。对于MTLPixelFormat.rgba32Float纹理,我将数据检索为:

let pixels: UnsafeMutablePointer<Float32> = texture.getPixels()
defer {
  pixels.deallocate()
}

let capacity = texture.width * texture.height * MemoryLayout<Float32>.stride

for i in stride(from: 0, to: capacity, by: 4) {
  let l     = pixels[i + 0]
  let a     = pixels[i + 1]
  let b     = pixels[i + 2]
  let alpha = pixels[i + 3]
}