Chapter 16 Bug in the Fireworks section

Hello Caroline:
I’m writing to report a small bug in Chapter 16, section Fireworks. The code in draw(in:):

guard let particleEncoder = commandBuffer.makeComputeCommandEncoder()
  else { return }
particleEncoder.setComputePipelineState(particlePipelineState)
particleEncoder.setTexture(drawable.texture, index: 0)
threadsPerGrid = MTLSizeMake(particleCount, 1, 1)
for emitter in emitters {
  let particleBuffer = emitter.particleBuffer
  particleEncoder.setBuffer(particleBuffer, offset: 0, index: 0)
  particleEncoder.dispatchThreads(threadsPerGrid,
                                  threadsPerThreadgroup: threadsPerThreadgroup)
}
particleEncoder.endEncoding()

causes a fatal error: validateBuiltinArguments:702: failed assertion `component 1: 32 must be <= 1 for id [[ thread_position_in_grid ]]'

I think the reason was that the threadsPerThreadgroup in dispatchThreads wasn’t updated for the second command encoder, it’s still defined as:

var width = pipelineState.threadExecutionWidth
var height = pipelineState.maxTotalThreadsPerThreadgroup / width
let threadsPerThreadgroup = MTLSizeMake(width, height, 1)

which is from the first command encoder.

Changing threadsPerThreadgroup to MTLSizeMake(particlePipelineState.threadExecutionWidth, 1, 1) solved the error for me.

P.S. I did move all the code in the Fireworks playground to a Xcode project, since I wasn’t able to successfully compile the code in the playground.

Hi @miraco - thanks for posting this issue here.

Did you try running the final playground sample code? Unfortunately Apple changed the way we create the library in the playground.

In Renderer.swift, the code in initializeMetal() should look like this:

    guard let device = MTLCreateSystemDefaultDevice(),
      let commandQueue = device.makeCommandQueue()

//      let path = Bundle.main.path(forResource: "Shaders",
//                                  ofType: "metal")

    else { return nil }
    
    let pipelineState: MTLComputePipelineState
    let particlePipelineState: MTLComputePipelineState
    
    do {
//      let input = try String(contentsOfFile: path,
//                             encoding: String.Encoding.utf8)
//      let library = try device.makeLibrary(source: input, options: nil)
      let library = device.makeDefaultLibrary()!
      guard let function = library.makeFunction(name: "compute"),

After changing that, my sample code works as is. I’m on a Silicon M1 Mac mini with Big Sur, Xcode 12.4.

What computer / GPU / OS / Xcode version do you have?

Hi Caroline,
The error that I had with the Fireworks playground in the final folder was:
Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value: file Fireworks_Sources/Renderer.swift, line 120
line 120 is:

guard let commandBuffer = commandQueue.makeCommandBuffer()

Screen Shot 2021-03-31 at 2.39.35 PM

After I update the initializeMetal function in Renderer, I got this:
Function compute is using language version 2.3 which is incompatible with this OS.

Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value: file Fireworks_Sources/Renderer.swift, line 120

I’m using MacBook Pro Late 2012, macOS Catalina 10.15.7, Graphics Intel HD Graphics 4000 1536 MB, Xcode 12.4

It appears that I can’t come up with a way around this on Catalina, except to create a project instead of a playground.

You can specify the Metal Shader Language version in a project, but there is no way to do it in a playground. Playgrounds are a nice idea, but sometimes more trouble than they are worth :smiley:

I see you’ve already created a project so hopefully you are beyond this point now. Thank you for alerting us to this problem.

1 Like