Group Group Group Group Group Group Group Group Group

SIMD BADACCESS Error?

Having a very strange error when building tutorials Chapter 5 onwards with the Arcball camera on macOS (Catalina 10.15.4 and 10.15.3):

I get a Thread 1: EXC_BAD_ACCESS (code=EXC_I386_GPFLT) in Camera.swift as part of the ArcBall logic. This only pops once the rotation calculation is executed.

Adding print statements in-between those lines fixes this. (can’t post second image in to show; new user)

Curious if anyone has had this problem, it looks like it is a problem from some people?
https://forums.developer.apple.com/message/402225#402225

2 Likes

Example of the print state solution

I have encountered this occasionally, but I haven’t yet dived into it to check the cause, which is something I suspect I can’t fix.

I get around it by assigning the whole [x, y, z] float3 value to the rotation at one time, and not by assigning rotation.x separately.

Ah! I should have tried that. I will reach out to Apple Dev and see if they can advise. It looked like 10.15.4 should have that update but it might be a patch coming later?

I spent most of the day trying to track this down as it just started happening to me also. And I have no idea what I did. Anyway, I made no real progress besides trying a ton of things as you can see from the following code and comments. Maybe you can see a pattern here. I cannot.

override func rotate(delta: float2) {
let sensitivity: Float = 0.005
print(rotation) // does not cause crash
print(delta) // does not cause crash
print(rotation.x) // does not cause crash
print(delta.x) // does not cause crash
rotation.y += sensitivity // does not cause crash
print(rotation.y) // does not cause crash
print(10.0 * sensitivity) // does not cause crash
let temp = 10.0 * sensitivity; print(temp) // does not cause crash
// var temp2 = 10.0 * sensitivity // causes crash at rotation.x += delta.y * sensitivity
// rotation.y = temp // causes crash
// rotation.y += 10.0 * sensitivity // causes crash
// rotation.y += delta.x * sensitivity // causes crash
rotation.x += delta.y * sensitivity // does not cause crash
print(rotation) // does not cause crash
print(rotation.x) // does not cause crash
rotation.x += delta.y * sensitivity // does not cause crash
// temp = rotation.x; print(temp)
// rotation.x = max(-Float.pi/2, min(rotation.x, Float.pi/2)) // causes crash
_viewMatrix = updateViewMatrix()
}

I also tried:
rotation += float3(delta,0) * sensitivity // causes crash

but that didn’t work.

Unfortunately this sounds like one of those things that depending on your CPU it will be a problem (until the patch for it is released)

my solution was as simple as:

override func rotate(delta: float2) {
    let sensitivity: Float = 0.005
    var x = rotation.x + delta.y * sensitivity
    x = max(-Float.pi/2, min(x, Float.pi/2))
    rotation = [
        x,
        rotation.y + delta.x * sensitivity,
        rotation.z
    ]
    _viewMatrix = updateViewMatrix()
  }
4 Likes

UPDATE: Here is a better version of it, bit more readable IMO:

override func rotate(delta: float2) {
    let sensitivity: Float = 0.005
    let y = rotation.y + delta.x * sensitivity
    var x = rotation.x + delta.y * sensitivity
    x = max(-Float.pi/2, min((x), Float.pi/2))
    rotation = [x, y, 0]
    _viewMatrix = updateViewMatrix()
5 Likes

I found that simply comment out the override of rotation property would work.

2 Likes

Oh interesting! now the question is if this is a SIMD alignment issue or if the didSet closure is doing some weirdness. I wonder if the ‘didSet’ events are getting tangled?

Unfortunately that method needs to be there to update the view matrix if the code changes the rotation of the camera (rather than the user through gestures).

For example, if you comment out that rotation method and in draw(in:), add a rotation:

timer += 0.005
camera.rotation.y = sin(timer)

Then the camera doesn’t rotate.

If you uncomment that override, that code doesn’t crash until you add

camera.rotation.x = sin(timer)

Then it does crash.

So I think that you’re right, it does seem to be the didSet that’s causing it, but I am loathe to change that method. Setting the entire rotation:

timer += 0.005
camera.rotation = [sin(timer), sin(timer), camera.rotation.z]

works, and I think is the way to go for the moment.

1 Like

So based on what David has said and a bit of sleuthing we have a very simple reproducible case now that I have sent to Apple to have a look at:

  • Create a new MacOS App using Storyboard

  • In the ViewController.swift file place the code below

  • Run the app and in the view that appears click and drag. You should get the BAD_ACCESS error.

//
//  ViewController.swift
//  AppleSIMDExample
//
//  Created by Andrew Paxson on 10/4/20.
//  Copyright © 2020 Andrew Paxson. All rights reserved.
//

import Cocoa
import simd

/* MARK: About the Bug
 
 This project is a segment of a larger project we have for a simple game engine with metal.
 There is a lot of matrix operations in the app so we utilize `didSet` heavily to update different
 matrices.
 
 In this example we have:
 - Storyboard with NSView
 - We add a pan gesture to capture the and convert it to rotation.
 - We are a "Camera" class that has a rotation property that utilizes a didSet
   This did set, in the real application, does some math for matrix updates which is not present here.
 
 Reproducing the Bug
 - Run the application and in the view that pops up just click and drag.
 
 
 Ways the bug disappears:
 A. Remove the 'didSet' from the camera rotation property.
 B. Instead set the rotation property as a whole, rather than the individual components.
 
 See the respective comments below for the code bits to uncomment/remove.
 
*/

class ViewController: NSViewController {
    
    let camera:Camera = Camera()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        addGestureRecognizers(to: view)
    }
    
    func addGestureRecognizers(to view: NSView) {
        let pan = NSPanGestureRecognizer(target: self, action: #selector(handlePan(gesture:)))
        view.addGestureRecognizer(pan)
    }
    
    @objc func handlePan(gesture: NSPanGestureRecognizer) {
        let translation = gesture.translation(in: gesture.view)
        let delta = SIMD2<Float>(Float(translation.x),
                           Float(translation.y))
        camera.rotate(delta: delta)
        gesture.setTranslation(.zero, in: gesture.view)
    }
}


class Camera {
    var rotation: SIMD3<Float> = [0, 0, 0] {
        // A. Remove this setter to remove the EXC_BAD_ACCESS
        didSet {
            _something()
        }
    }
    func rotate(delta: SIMD2<Float>) {
        print("rotate delta: \(delta)")
        
        // B: Uncomment this, and comment the two lines under 'Bug Here' below
//        rotation = [ rotation.x + delta.x, rotation.y + delta.y, rotation.z]
        
        // Bug Here
        rotation.y += delta.x
        rotation.x += delta.y
        
    }
    
    func _something() {
        print("_something()")
    }
}
1 Like

Thanks for putting that together :clap:

Hello

Begining to learn Metal … stuck on Chapter5 with the bug you describre.

I thought I had a personal issue.
I see I am not alone.

I will stay tune …

Take care

Bertrand

@behr - don’t be stuck! Use the work-around as described above!

Oh, thank you Caroline for you message.

Do not worry. I read the entire post and tested successfully the comment of “overide rotation”…

Very interesting book so far. Thank you for your involvment in writing this book. I hope I will reach the end (I begun yesterday)…

Regards

Behr

1 Like

This bug seems to be fixed in Xcode 12 beta 1. Hopefully Apple doesn’t break it again before release. :laughing:

1 Like

@exsangus Thank you for sharing this - much appreciated!

Hello all! I got around it by adding “super.” to the rotation assignments in the rotate function. If anyone has the time and knowhow, I’d appreciate hearing why that’s a better or worse solution than the others referenced here. I’m taking it by the references to this being a bug in Xcode that this should not actually be necessary?

I’ve been thinking about what I meant by “better or worse solution” and I realized what I meant was: I really don’t know what I’m doing and while I can see that my solution works, I’m not certain it doesn’t have side effects. I guess I’m just asking if there’s something I should be aware of that makes it a bad solution - any guidance is appreciated.

Hi @barnetta :slight_smile:

I would think that super. is a good solution, because ArcballCamera inherits from Camera, which inherits from Node, which is where rotation is defined. So super points more closely to where the property is held in memory. But that’s guesswork.

However, in Xcode 12, it’s now fixed, and should work fine without using super.