无法使用 MTKTextureLoader 将大型 jpeg 加载到 MTLTexture 中
Can't load large jpeg into a MTLTexture with MTKTextureLoader
我正在尝试将大图像加载到 MTLTexture 中,它适用于 4000x6000 图像。但是当我尝试使用 6000x8000 时,它不能。
func setTexture(device: MTLDevice, imageName: String) -> MTLTexture? {
让 textureLoader = MTKTextureLoader(设备:设备)
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
}
非常基本的代码。我 运行 它在 iPad Pro 中,配备 A9 芯片,GPU 系列 3。它应该处理这么大的纹理。如果它不接受这个尺寸,我是否应该以某种方式手动平铺它?在那种情况下,最好的方法是什么:使用 MTLRegionMake 复制字节,在 Core Image 或 Core Graphics 上下文中切片...
感谢任何帮助
我之前遇到过这个问题,纹理会加载到一台设备上,而不是另一台设备上。我认为这是纹理加载器的错误。
您可以使用 CGImage 和 CGContext 手动加载纹理,将图像绘制到上下文中。创建一个 MTLTexture 缓冲区,然后使用 MTLRegion 将字节从 CGContext 复制到纹理中。
这不是万无一失的,你必须确保为金属缓冲区使用正确的像素格式,否则你会得到奇怪的结果,所以你要么为你正在导入的一种特定格式的图像编码,要么很多检查。 Apples 的 Basic Texturing example 展示了如何在使用 MTLRegion 将字节写入纹理之前更改颜色顺序。
根据您的有用评论,我决定手动加载它绘制到 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
我正在尝试将大图像加载到 MTLTexture 中,它适用于 4000x6000 图像。但是当我尝试使用 6000x8000 时,它不能。
func setTexture(device: MTLDevice, imageName: String) -> MTLTexture? { 让 textureLoader = MTKTextureLoader(设备:设备)
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
}
非常基本的代码。我 运行 它在 iPad Pro 中,配备 A9 芯片,GPU 系列 3。它应该处理这么大的纹理。如果它不接受这个尺寸,我是否应该以某种方式手动平铺它?在那种情况下,最好的方法是什么:使用 MTLRegionMake 复制字节,在 Core Image 或 Core Graphics 上下文中切片...
感谢任何帮助
我之前遇到过这个问题,纹理会加载到一台设备上,而不是另一台设备上。我认为这是纹理加载器的错误。
您可以使用 CGImage 和 CGContext 手动加载纹理,将图像绘制到上下文中。创建一个 MTLTexture 缓冲区,然后使用 MTLRegion 将字节从 CGContext 复制到纹理中。
这不是万无一失的,你必须确保为金属缓冲区使用正确的像素格式,否则你会得到奇怪的结果,所以你要么为你正在导入的一种特定格式的图像编码,要么很多检查。 Apples 的 Basic Texturing example 展示了如何在使用 MTLRegion 将字节写入纹理之前更改颜色顺序。
根据您的有用评论,我决定手动加载它绘制到 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