预加载SKTextureAtlas时遇到性能下降:

let textureAtlas = SKTextureAtlas(named: atlasName)
textureAtlas.preload(completionHandler: {
    ...
})

所谓的性能下降,是指FPS在短时间内下降到约50。

我用Time Profiler中的Instruments测试了它,并验证了这项工作确实是在工作线程上完成的,如documentation中所述。

下面的图像显示了由预加载图集引起的尖峰的Time Profiler捕获。如您所见,据我所知,大多数峰值是由2个工作线程引起的,它们似乎都在加载图像数据。但是,这不应导致主线程IMHO的性能下降。

ios - SpriteKit : performance hit while preloading SKTextureAtlas-LMLPHP

注1 :我正在预加载的.spriteatlas没那么大:4个 Assets 的大约1000x1000的大小。

注2 :我正在使用iPhone 6,iOS 10,Xcode 8进行测试。

注3 :没有同时进行其他大量工作; CPU一直徘徊在30%左右。 GPU也是如此。

注4 :在需要来自该 map 集的任何纹理之前,请求 map 集预加载,因此应该有足够的时间进行预加载。

任何帮助/方向,不胜感激!

更新

发生预加载的完整代码块:
let updateGroup = DispatchGroup()

for assetDefinition in assetContainmentDefinitions {

    let assetName = assetDefinition.assetName

    // Check if asset is not needed anymore and clear the cache with it
    if progress >= assetDefinition.range.to {
        if cachedAssets[assetName] != nil {
            cachedAssets[assetName] = nil
        }
    }
    // Check if asset is needed and if it's not already loading then preload and cache it
    else if progress >= assetDefinition.range.from {

        if currentlyLoadingAssets.contains(assetName) == false &&
            cachedAssets[assetName] == nil {

            currentlyLoadingAssets.append(assetName)

            // Enter dispatch group
            updateGroup.enter()

            switch assetDefinition.assetType {
            case .textureAtlas:

                let textureAtlas = SKTextureAtlas(named: assetName)
                textureAtlas.preload(completionHandler: {

                    DispatchQueue.main.async { [weak self] in

                        self?.cachedAssets[assetName] = textureAtlas
                        self?.currentlyLoadingAssets.remove(object: assetName)

                        // Leave dispatch group after preload is done
                        updateGroup.leave()
                    }
                })

            case .texture:

                let texture = SKTexture(imageNamed: assetName)
                texture.preload(completionHandler: {

                    DispatchQueue.main.async { [weak self] in

                        self?.cachedAssets[assetName] = texture
                        self?.currentlyLoadingAssets.remove(object: assetName)

                        // Leave dispatch group after preload is done
                        updateGroup.leave()
                    }
                })
            }
        }
    }
}

// Call completion after the dispatch group is fully completed
if let completion = completion {
    updateGroup.notify(queue: DispatchQueue.main, execute: completion)
}

更新2

我创建了一个空项目,只剩下了Atlas预加载块。性能下降仍然会发生。我尝试过使用多个 map 集,甚至只使用一项 Assets 的 map 集。

在这个空的新项目中,我也尝试了@Sez的建议(请参见下面的内容),但是在那种情况下,甚至没有调用完成块,这似乎是SKTextureAtlas类中的另一个错误。 (?!)
let atlas = SKTextureAtlas(dictionary: ["texture1": UIImage(named: "texture1")!])

atlas.preload(completionHandler: { [weak self] in
    print("COMPLETION BLOCK NOT CALLED")
    self?.cachedAtlas = atlas
})

更新3

我尝试删除.spriteatlas并使用相同的纹理创建.atlas,并且(几乎)没有性能降低。但是,.atlas不支持切片,这就是为什么我要首先使用.spriteatlas的原因。

最佳答案

issues plaguing SKTextureAtlas(Apple Dev论坛帖子)。

尝试使用提供了SKTextureAtlas:withDictionary:字典,method described on another StackOverflow post[String:UIImage]创建纹理图集,看看是否有帮助。

更新:如果您希望preload of the SKTexture在后台线程中发生,我会专门编写它,而不是依赖preload便捷功能。

let atlas: SKTextureAtlas
let myImages: [String: UIImage] = getImages()
let globalQueue = DispatchQueue.global()
globalQueue.async {
    let atlas = SKTextureAtlas(withDictionary:myImages)
    for (k,v) in myImages {
        let tex = atlas.textureNamed(k)
        print(tex.size()) // force load
    }
    DispatchQueue.main.async {
        completionHandler(atlas)
    }
}

关于app slicing,只要您将 Assets 放置在 Assets 目录中,就应该对其进行切片。将构建上传到iTunesConnect之后,您可以看到反射(reflect)出此情况的App Store大小的报告。

ios - SpriteKit : performance hit while preloading SKTextureAtlas-LMLPHP

我有一个录制的直播视频,其中显示了此导入过程。很抱歉,它的时间很长(2hrs +),但是这里的链接恰好发生在导入到Sprite表中的那一刻。

https://youtu.be/Ic9Wnux8vd8?t=1h17m

按照我在这里显示的方式进行操作,您会得到带有切片图像的Sprite map 集。如果需要,我的脚本(我在剪辑的前面已经演示过)是on my GitHub

关于ios - SpriteKit : performance hit while preloading SKTextureAtlas,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40834615/

10-09 02:41