SKTextureAtlas no longer uses textures in iOS 10

It seems that when pulling textures from a texture atlas, I now generate new textures instead of using the same texture for different sprites with iOS 10. On iOS 9, this works as expected. Anyone else having this problem? Perhaps I skipped the step, which is now part of iOS 10.

Notes: I created a sample project and created a new atlas, and then just dragged the spaceship to @ 1x, I also tried preloading, and that also did nothing.

The code:

let atlas = SKTexturAtlas(named:"Sprites") var texture = atlas.textureNamed("Spaceship") print("\(Unmanaged.passUnretained(texture)),\(Unmanaged.passUnretained(texture).toOpaque())") texture = atlas.textureNamed("Spaceship") print("\(Unmanaged.passUnretained(texture)),\(Unmanaged.passUnretained(texture).toOpaque())") 

Edit: to get around comparison problems, I use the description property to compare if 2 textures are equal. For this, however, you cannot use 2 atlases, each of which contains a texture with the exact name and size. I will never get into this situation, but for those who seek help, keep this in mind.

+6
source share
3 answers

To get around this problem, I had to come up with a way to cache textures so that it does not duplicate:

 private var textureCache = [String: SKTexture]() extension SKTextureAtlas { func texturesWithNames(_ names:[String]) -> [SKTexture] { var textures = [SKTexture]() names.forEach({textures.append(textureNamed($0))}) return textures } func cachedTextureWithName(_ name:String) -> SKTexture { if textureCache[name] == nil { textureCache[name] = textureNamed(name) } return textureCache[name]! } func cachedTexturesWithNames(_ names:[String]) -> [SKTexture] { var textures = [SKTexture]() names.forEach({textures.append(cachedTextureWithName($0))}) return textures } func clearCache() { textureCache = [String: SKTexture]() } } extension SKTexture { var name : String { return self.description.slice(start: "'",to: "'")! } } 
+1
source

I am doing the same test and getting the same results.

I'm not 100% sure, but it seems like during development Swift 3 was suggested here to change Unmanaged to use UnsafePointer .

But if you try to do:

 func address<T: AnyObject>(o: T) -> String{ let addr = unsafeBitCast(o, to: Int.self) return NSString(format: "%p", addr) as String } 

Using

 print(address(o: texture)) 

in iOS9 you have the correct values, in iOS10 the wrong results.

enter image description here

I think you're right, we are facing a mistake (another ..)

+3
source

Does the other physical address have a texture referencing "the same texture", is there really a problem?

I started the default model game project, but installed it for Obj-C. I have a texture atlas that will be something like the image below. However, note that I passed this through TexturePacker. Thus, the actually created Xcode atlas is different.

enter image description here

I do as you said and created 2 textures with the same name.

 self.myTextureAtlas = [SKTextureAtlas atlasNamed:@"MyTexture"]; self.tex0 = [self.myTextureAtlas textureNamed:@"tex0"]; self.tex1 = [self.myTextureAtlas textureNamed:@"tex0"]; 

As you said, pointers to tex0 and tex1 different. So at least there is a match between Swift and Obj-C.

However, I do not think this is a problem / error. I suspect that they changed the implementation, so the returned SKTexture is a new "instance", however the basic texture remains the same.

I will talk about OpenGL, as this is what I write in my machines. Metal will still have similarities. A basic sub-texture does have only 2 important properties: the name of the texture (this is the name of the OpenGL texture) and UVs. If you were thinking about what would be considered โ€œequalityโ€ for Equatable , most likely it would experience equality against these two items. The name of the texture is the name of the texture of the atlas, and UV is the UV in the atlas, which represent the region of a particular substructure.

To test this hypothesis, I launched GPU frame capture. With Xcode 8, this seems rather unsuccessful. Using metal, it crashed in 100% of cases. I made him use OpenGL and managed to get a frame capture. As expected, when I look at all the texture resources, I see only one texture for my atlas.

enter image description here

Texture # 3 is MyTexture.

If I unload a texture that seems UV, I see that they are the same:

Tex0 Rect 0.001618 0.793765 0.1339159 0.203837

Tex1 Rect 0.001618 0.793765 0.1339159 0.203837

Based on this, it would seem that self.tex0 and self.tex1 , although they have different physical addresses, still point to the same sub-texture.

Please note that I no longer use SpriteKit. My current renderer uses texture descriptors, however, when restoring, you can handle objects with different physical addresses. They are still playing out the true texture, since they are still referring to the same underlying texture instance.

I assume that in fact I do not see a problem with the difference pointers, provided that they still refer to the same base texture (i.e. texture memory is no longer allocated).

+1
source

Source: https://habr.com/ru/post/1011820/


All Articles