ios - 检测 MTLTexture 是否为空白

标签 ios swift metal

我试图通过计算每个像素的所有 R G B 和 A 分量的总和来确定 MTLTexture(bgra8Unorm 格式)是否为空白。

此函数旨在通过在将纹理复制到指针后在内存中添加相邻的 float 来执行此操作。但是我已经确定这个函数最终会返回 false nomatter 给定的 MTLTexture。

这个函数有什么问题?

func anythingHere(_ texture: MTLTexture) -> Bool {
        let width = texture.width
        let height = texture.height
        let bytesPerRow = width * 4

        let data = UnsafeMutableRawPointer.allocate(bytes: bytesPerRow * height, alignedTo: 4)
        defer {
            data.deallocate(bytes: bytesPerRow * height, alignedTo: 4)
        }

        let region = MTLRegionMake2D(0, 0, width, height)
        texture.getBytes(data, bytesPerRow: bytesPerRow, from: region, mipmapLevel: 0)
        var bind = data.assumingMemoryBound(to: UInt8.self)

        var sum:UInt8 = 0;
        for i in 0..<width*height {
            sum += bind.pointee
            bind.advanced(by: 1)
        }
        return sum != 0
}

最佳答案

Matthijs 的改变是必要的,但这种方法的正确性还存在一些其他问题。

您实际上只迭代了 1/4 的像素,因为您是按字节步进并且循环的上限是 width * height而不是 bytesPerRow * height .

此外,计算像素总和并不是您真正想要的。您可以通过在遇到非零值 (if bind.pointee != 0) 时立即返回 true 来节省一些工作。

(顺便说一句,如果您将大于 255 的值累积到 UInt8 中,Swift 的整数溢出保护实际上会引发异常。我想您可以使用更大的整数,或者使用 sum = sum &+ bind.pointee 禁用溢出检查,但同样,在第一个非透明像素上打破循环将节省一些时间并防止累加器“翻转”到恰好为 0 时的误报。)

这是对我有用的函数版本:

func anythingHere(_ texture: MTLTexture) -> Bool {
    let width = texture.width
    let height = texture.height
    let bytesPerRow = width * 4

    let data = UnsafeMutableRawPointer.allocate(byteCount: bytesPerRow * height, alignment: 4)
    defer {
        data.deallocate()
    }

    let region = MTLRegionMake2D(0, 0, width, height)
    texture.getBytes(data, bytesPerRow: bytesPerRow, from: region, mipmapLevel: 0)
    var bind = data.assumingMemoryBound(to: UInt8.self)

    for _ in 0..<bytesPerRow * height {
        if bind.pointee != 0 {
            return true
        }
        bind = bind.advanced(by: 1)
    }
    return false
}

请记住,在 macOS 上,默认 storageMode纹理是 managed ,这意味着当它们在 GPU 上被修改时,它们的内容不会自动同步回主内存。您必须明确使用 blit 命令编码器来自己同步内容:

let syncEncoder = buffer.makeBlitCommandEncoder()!
syncEncoder.synchronize(resource: texture)
syncEncoder.endEncoding()

关于ios - 检测 MTLTexture 是否为空白,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49375701/

相关文章:

ios - 由于未捕获的异常,子类化多个 UITableViewCells 终止应用程序

ios - 添加带有自定义文本的新 UITableView 行

swift - self.tabBarController?.selectedIndex 并在另一个 View Controller 中执行功能

json - 根据嵌套字符串的值过滤 JSON

ios - 如果语句没有改变全局变量 swift

ios - 在 ASIFormDataRequest iOS dev 中获取异步响应和同步调用超时

iphone - 为什么我应该更喜欢 ASIHTTPRequest 而不是 NSURLConnection 从 Web 下载文件?

gpgpu - 您可以使用 Apple 的 Metal 进行通用 GPU 编程吗?

ios - 图形 - 在缓冲区之间混合而不用考虑首先渲染哪个缓冲区

objective-c - MetalKit - 如何使用(MTKTextureLoader 方法)newTextureWithContentsOfURL 的选项?