无法使用MTKTextureLoader将大型jpeg加载到MTLTexture中

问题描述 投票:0回答:2

我正在尝试将大图像加载到MTLTexture中,它可以处理4000x6000图像。但是,当我尝试6000x8000它不能。

func setTexture(device:MTLDevice,imageName:String) - > MTLTexture? {let textureLoader = MTKTextureLoader(device:device)

    var texture: MTLTexture? = nil

    //  In iOS 10 the origin was changed.
    let textureLoaderOptions: [MTKTextureLoader.Option: Any]
    if #available(iOS 10.0, *) {
        let origin = MTKTextureLoader.Origin.bottomLeft.rawValue
        textureLoaderOptions = [MTKTextureLoader.Option.origin : origin]
    } else {
        textureLoaderOptions = [:]
    }

    if let textureURL = Bundle.main.url(forResource: imageName, withExtension: nil, subdirectory: "Images") {
        do {
            texture = try textureLoader.newTexture(URL: textureURL, options: textureLoaderOptions)
        } catch {
            print("Texture not created.")
        }
    }
    return texture
}

非常基本的代码。我在带有A9芯片,GPU系列3的iPad Pro中运行它。它应该处理这么大的纹理。如果它不接受这个尺寸,我应该以某种方式手动平铺它吗?在这种情况下,最好的方法是什么:使用MTLRegionMake复制字节,在Core Image或Core Graphics上下文中切片......

我感谢任何帮助

metal core-image metalkit
2个回答
0
投票

之前我遇到过这个问题,纹理会加载到一个设备而不是另一个设备上。我认为这是纹理加载器的一个bug。

您可以使用CGImage和CGContext手动加载纹理,将图像绘制到上下文中。创建一个MTLTexture缓冲区,然后使用MTLRegion将CGContext中的字节复制到纹理中。

这不是万无一失的,您必须确保为金属缓冲区使用正确的像素格式,否则您将获得奇怪的结果,因此您要么编码要导入的特定格式的图像,要么进行大量检查。苹果的Basic Texturing example展示了如何在使用MTLRegion将字节写入纹理之前更改颜色顺序。


0
投票

根据您的有用评论,我决定手动将其加载到CGContext并复制到MTLTexture。我在下面添加解决方案代码。每次创建纹理时都不应创建上下文,最好将其放在函数外部并继续重复使用。

    // Grab the CGImage, w = width, h = height...

    let context = CGContext(data: nil, width: w, height: h, bitsPerComponent: bpc, bytesPerRow: (bpp / 8) * w, space: colorSpace!, bitmapInfo: bitmapInfo.rawValue)

    let flip = CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: CGFloat(h))
    context?.concatenate(flip)
    context?.draw(cgImage, in: CGRect(x: 0, y: 0, width: CGFloat(w), height: CGFloat(h)))

    let textureDescriptor = MTLTextureDescriptor()
    textureDescriptor.pixelFormat = .rgba8Unorm
    textureDescriptor.width = w
    textureDescriptor.height = h

    guard let data = context?.data else {print("No data in context."); return nil}

    let texture = device.makeTexture(descriptor: textureDescriptor)
    texture?.replace(region: MTLRegionMake2D(0, 0, w, h), mipmapLevel: 0, withBytes: data, bytesPerRow: 4 * w)

    return texture
© www.soinside.com 2019 - 2024. All rights reserved.