iOS13 SceneKit Error – Purging never freed texture - swift

I have an ARKit app that runs fine on iOS 12.x. On iOS 13 I encounter the following error in the console log:
[SceneKit] Error: Purging never freed texture <AGXA9FamilyTexture: 0x11d688240>
label = <none>
textureType = MTLTextureType2D
pixelFormat = MTLPixelFormatR16Float
width = 240
height = 1
depth = 1
arrayLength = 1
mipmapLevelCount = 1
sampleCount = 1
cpuCacheMode = MTLCPUCacheModeDefaultCache
storageMode = MTLStorageModePrivate
hazardTrackingMode = MTLHazardTrackingModeTracked
resourceOptions = MTLResourceCPUCacheModeDefaultCache MTLResourceStorageModePrivate MTLResourceHazardTrackingModeTracked
usage = MTLTextureUsageShaderRead MTLTextureUsageShaderWrite
shareable = 0
framebufferOnly = 0
purgeableState = MTLPurgeableStateNonVolatile
swizzle = [MTLTextureSwizzleRed, MTLTextureSwizzleGreen, MTLTextureSwizzleBlue, MTLTextureSwizzleAlpha]
isCompressed = 0
parentTexture = <null>
parentRelativeLevel = 0
parentRelativeSlice = 0
buffer = <null>
bufferOffset = 512
bufferBytesPerRow = 0
allowGPUOptimizedContents = YES
label = <none>
It repeats every few milliseconds and clutters the whole log. I was not able to narrow down where it comes from.
The interesting part is, that this even occurs when not a single node is present in the scene. If I remove the entire sceneView from the view then it disappears...(not an option)
Anybody any idea or hint how to track this down ?
Thanks

I fixed this issue by updating the setting of the scene camera:
var sceneView: ARSCNView!
...
sceneView.pointOfView?.camera?.wantsHDR = false
Hope this helps.

I have found the problem code line. In iOS 13 any call to
SceneView.snapshot()
produces that error. The apple docs say:
This method is thread-safe and may be called at any time.
but this seems to have changed in iOS13. I will file a bug report not hoping for a fast solution ;-)

Related

SIGABRT "The following Metal object is being destroyed while still required to be alive by the command buffer" in macCatalyst randomly

I have macCatalyst app that recently gets some random crashes. Searched everywhere but without finding any good leads. My guess is that it's related to memory or too many views visible on the screen. I do not get a good stack trace, but this it what's showing in the log:
-[MTLDebugDevice notifyExternalReferencesNonZeroOnDealloc:]:2951: failed assertion `The following Metal object is being destroyed while still required to be alive by the command buffer 0x7f8cd811c600 (label: <no label set>):
<MTLToolsObject: 0x7f8b0f9e3d60> -> <MTLIGAccelTexture: 0x7f8cd8566a00>
label = CAMetalLayer Drawable
textureType = MTLTextureType2D
pixelFormat = MTLPixelFormatBGRA8Unorm_sRGB
width = 772
height = 1372
depth = 1
arrayLength = 1
mipmapLevelCount = 1
sampleCount = 1
cpuCacheMode = MTLCPUCacheModeDefaultCache
storageMode = MTLStorageModeManaged
hazardTrackingMode = MTLHazardTrackingModeTracked
resourceOptions = MTLResourceCPUCacheModeDefaultCache MTLResourceStorageModeManaged MTLResourceHazardTrackingModeTracked
usage = MTLTextureUsageShaderRead MTLTextureUsageShaderWrite MTLTextureUsageRenderTarget MTLTextureUsagePixelFormatView
shareable = 0
framebufferOnly = 0
purgeableState = MTLPurgeableStateNonVolatile
swizzle = [MTLTextureSwizzleRed, MTLTextureSwizzleGreen, MTLTextureSwizzleBlue, MTLTextureSwizzleAlpha]
isCompressed = 0
parentTexture = <null>
parentRelativeLevel = 0
parentRelativeSlice = 0
buffer = <null>
bufferOffset = 0
bufferBytesPerRow = 0
iosurface = 0x600002533060
iosurfacePlane = 0
allowGPUOptimizedContents = YES'
-[MTLDebugDevice notifyExternalReferencesNonZeroOnDealloc:]:2951: failed assertion `The following Metal object is being destroyed while still required to be alive by the command buffer 0x7f8cd811c600 (label: <no label set>):
<MTLToolsObject: 0x7f8b0f9e3d60> -> <MTLIGAccelTexture: 0x7f8cd8566a00>
label = CAMetalLayer Drawable
textureType = MTLTextureType2D
pixelFormat = MTLPixelFormatBGRA8Unorm_sRGB
width = 772
height = 1372
depth = 1
arrayLength = 1
mipmapLevelCount = 1
sampleCount = 1
cpuCacheMode = MTLCPUCacheModeDefaultCache
storageMode = MTLStorageModeManaged
hazardTrackingMode = MTLHazardTrackingModeTracked
resourceOptions = MTLResourceCPUCacheModeDefaultCache MTLResourceStorageModeManaged MTLResourceHazardTrackingModeTracked
usage = MTLTextureUsageShaderRead MTLTextureUsageShaderWrite MTLTextureUsageRenderTarget MTLTextureUsagePixelFormatView
shareable = 0
framebufferOnly = 0
purgeableState = MTLPurgeableStateNonVolatile
swizzle = [MTLTextureSwizzleRed, MTLTextureSwizzleGreen, MTLTextureSwizzleBlue, MTLTextureSwizzleAlpha]
isCompressed = 0
parentTexture = <null>
parentRelativeLevel = 0
parentRelativeSlice = 0
buffer = <null>
bufferOffset = 0
bufferBytesPerRow = 0
iosurface = 0x600002533060
iosurfacePlane = 0
allowGPUOptimizedContents = YES'
I'm running on a Intel Mac mini with 32Gb memory. It often crashes often when showing a MapView on screen. But also in some other cases.
Edit: Could be related to programatically zooming in animated in a MapView on MacCatalyst. A workaround is for now to disable the animation. Will research more.

Loop for variables (Xcode 9 - swift 4)

I have I think a stupid question for you, but I start Xcode just one week ago and I have a problem with a loop condition.
for index in 1...4 {
AvatarPlayer1.layer.borderWidth = 4
AvatarPlayer1.layer.cornerRadius = 8
AvatarPlayer1.layer.borderColor = UIColor.white.cgColor
AvatarPlayer1.layer.masksToBounds = false
AvatarPlayer1.clipsToBounds = true //Mask for picture
}
How can I change the 1 value by for number in the loop.
I have try + , + \(index), + index.
You cannot change a variable name in code. Instead, start with an array of your four AvatarPlayer objects and cycle through the array:
let myArrayOfAvatarPlayers = [AvatarPlayer1, AvatarPlayer2, AvatarPlayer3, AvatarPlayer4]
for thisPlayer in myArrayOfAvatarPlayers {
thisPlayer.layer.borderWidth = 4
thisPlayer.layer.cornerRadius = 8
thisPlayer.layer.borderColor = UIColor.white.cgColor
thisPlayer.layer.masksToBounds = false
thisPlayer.clipsToBounds = true //Mask for picture
}
In addition to matt's answer, you could move the setup up stuff to the object init or setup method.
After that, you could use init(repeating:count:) for the list's init. See: https://developer.apple.com/documentation/swift/array/1641692-init

SecKeyEncrypt returns error -50 and 0 cipherSize

I am porting a PKI api to Swift 2.2 and found the following error. Everything works fine in Objective-C.
The data object to be encrypted is 32 bytes in size. This is the code I am using.
let buflen = 64
var cipherBuffer = UnsafeMutablePointer<UInt8>.alloc(buflen)
cipherBuffer[buflen] = 0 // zero terminate
var cipherLength: Int = 0
var statusCode: OSStatus?
let dataPointer = UnsafePointer<UInt8>(data.bytes)
statusCode = SecKeyEncrypt(publicKey, SecPadding.PKCS1, dataPointer, data.length, cipherBuffer, &cipherLength)
This results in an error -50 and 0 cipher length.
I am doing an hexdump of the public key and the dataPointer to ensure they are OK, but can´t find the problem with the SecKeyEncrypt call
Any help will be appreciated
After some research I found a solution to the problem
I was creating the cipherBuffer using alloc and zero terminating the array, as follows:
let buflen = 64
var cipherBuffer = UnsafeMutablePointer<UInt8>.alloc(buflen)
cipherBuffer[buflen] = 0 // zero terminate
I tried the following approach and it works fine.
let blockSize = SecKeyGetBlockSize(publicKey) //64
var cipherBuffer = [UInt8](count: Int(blockSize), repeatedValue: 0)
Given that both approaches reported a block of 64 bytes with 0x00 using hexDump, I did a quick test and reviewed the previous code and found that removing the line with "cipherBuffer[buflen] = 0" fixes the problem.
It seems that it has to do with the zero termination of the array, or I may have done something weird.

Change SpriteNode PhysicsBody Size at Run Time

I want to be able to change a node's physicsBody height when the user swipes downwards, but have not been able to find out how to do this, beside resetting the entire physicsBody.
When I originally load the node, I use the below code:
nodeHero.color = UIColor .grayColor()
nodeHero.size.width = 20
nodeHero.size.height = 45
nodeHero.position.x = -frame.size.width/2 + 45
nodeHero.position.y = pointMainY + 30 + nodeHero.size.height/2
nodeHero.zPosition = 110
nodeHero.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(nodeHero.size.width, nodeHero.size.height))
nodeHero.physicsBody?.mass = 1
nodeHero.physicsBody?.angularVelocity = 0
nodeHero.physicsBody?.allowsRotation = false
nodeHero.physicsBody?.restitution = 0
nodeHero.physicsBody?.categoryBitMask = bitHero
addChild(nodeHero)
And when I swipe down, I want to be able to do something like this (this doesn't work):
nodeHero.size.height = 28
nodeHero.physicsBody?.size.height = 28
But instead I have to use the nodeHero.physicsBody = SKPhysicsBody() again, which resets all the other physicsBody properties, so I have to do this:
nodeHero.size.height = 28
nodeHero.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(nodeHero.size.width, nodeHero.size.height))
nodeHero.physicsBody?.mass = 1
nodeHero.physicsBody?.angularVelocity = 0
nodeHero.physicsBody?.allowsRotation = false
nodeHero.physicsBody?.restitution = 0
nodeHero.physicsBody?.categoryBitMask = bitHero
According to SpriteKit documentation the area of a SKPhysicsBody can't be modified, so you need to create another SKPhysicsBody instance and copy the values you want to keep from the previous instance.

as3 air for ios get screen device resolution

I am trying to set my mc to the exact screen size on an iPhone using air in as3.
I have tired:
import flash.display.Screen;
import flash.geom.Rectangle;
var mainScreen:Screen = Screen.mainScreen;
var screenBounds:Rectangle = mainScreen.bounds;
/// Does not work - comes out 320 by 480
w.text = ""+screenBounds.width+"";
h.text = ""+screenBounds.height+"";
BG.height = screenBounds.height;
BG.width = screenBounds.width;
/// Does not work - comes out 320 by 480
w.text = ""+Capabilities.screenResolutionX+"";
h.text = ""+Capabilities.screenResolutionY+"";
BG.height = Capabilities.screenResolutionY;
BG.width = Capabilities.screenResolutionX;
/// Does not work - comes out 320 by 480
w.text = ""+stage.fullScreenwidth+"";
h.text = ""+stage.fullScreenHeight+"";
BG.height = stage.fullScreenHeight;
BG.width = stage.fullScreenWidth;
/// Works BUT... it does NOT stretch to fit the stage.
/// I am starting with android screen size and it shrinks it proportionally
/// which means there is space on top or bottom or left side.
w.text = ""+stage.stageWidth+"";
h.text = ""+stage.stageHeight+"";
BG.height = stage.stageHeight;
BG.width= stage.stageWidth;
You can try to play around with stage.scaleMode :
stage.scaleMode = StageScaleMode.SHOW_ALL;
or
stage.scaleMode = StageScaleMode.EXACT_FIT;
If it is coming out 320x480 and you are saying that is wrong, can I assume you are using an iPhone 4S? If so, go into the App Descriptor XML file. Toward the bottom (generally one of the last items in the file), there should be this line.
<requestedDisplayResolution>standard</requestedDisplayResolution>
If it is commented out or set to "standard", this would be your issue. Change it to say "high" and that will enable Retina support. "standard" scales the non-retina display (320x480 on iPhone, 1024x768 on iPad) up. "high" will give you the correct display resolution.
Here is a detailed explanation:
http://www.adobe.com/devnet/air/articles/multiple-screen-sizes.html
if someone else is having issues getting the screen resolution for ios. What is happening is that there is no enough time between the completed loaded swf and the time you call the screen size.
For my app I need the swf with no scale because I am setting all my clips size and positions by setting a relative value to screen size in percent.
if my stage is 800x1280 and I have a clip with height = 100, width = 100;
then is the same to say that my clips.height = int(stage.stageWidth * 0.125);
as 100 * 100 / 800 = 12.5; | 100 is the 12.5% from 800;
The trick is that for your first frame (if you are using flash)
just set the stage scale and wait for full load the swf, and just that.
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
var loadTimer:Timer = new Timer(10);
loadTimer.addEventListener(TimerEvent.TIMER, loading);
loadTimer.start();
function loading(evt){
if(root.loaderInfo.bytesLoaded == root.loaderInfo.bytesTotal){
loadTimer.stop();
loadTimer.removeEventListener(TimerEvent.TIMER, loading);
gotoAndPlay(2);
}
}
then in the frame 2 you can call the stage.stageWidth and it will give you the real size, as you have give enough time to the app get that value.
var stageW:int = stage.stageWidth;
var stageH:int = stage.stageHeight;
I hope it can help, thanks