Converting RGBA32Float MTLTextures to NSImage

275 Views Asked by At

I've tried a bunch of techniques like using CIImage or copying the data into a buffer of uint_32ts, but they have all had their issues. The simplest I have found so far is:


extension MTLTexture {
    
    func toImage() -> NSImage? {
        
        assert (pixelFormat == .rgba32Float)
        let rowByteCount = width * 16
        let bytes = UnsafeMutablePointer<Float>.allocate(capacity: width * height * 4)
        defer {
            bytes.deallocate()
        }
        getBytes(bytes,
                 bytesPerRow: rowByteCount,
                 from: MTLRegion(origin: MTLOrigin(x: 0, y: 0, z: 0),
                                 size: MTLSize(width: width, height: height, depth: 1)),
                 mipmapLevel: 0)
        let context = CGContext(data: bytes,
                                width: width,
                                height: height,
                                bitsPerComponent: 32,
                                bytesPerRow: rowByteCount,
                                space: CGColorSpaceCreateDeviceRGB(),
                                bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.floatComponents.rawValue)
        guard let cgImage = context?.makeImage() else { print("Failed making cgImage"); return nil }
    
        return NSImage(cgImage: cgImage, size: NSSize(width: width, height: height))
    }
    
}

This creates an image of the correct size, but it is completely transparent. Sometimes when zooming in with Preview, an outline of certain features in the image will flicker, but once the image renders it disappears. I made sure to synchronize the image, and I have made sure that the bytes buffer has non-zero values. I have also tried using a buffer of SIMD4<Float>s instead of Floats, but it produced the same result.

0

There are 0 best solutions below