Reputation: 3203
I've found a working example of a Metal app for macOS, written in Objective-C. It shows how to work with multiple GPUs, and it draws some pretty things too. I've pared it down quite a bit to get the most minimal example I can. It's here, as is my (attempted) translation to Swift.
Although the code is a bit involved, I think the problem is in a fairly contained place: drawing to the view/window/screen or whatever. Everything seems to be working perfectly except for the draw itself. I am guessing that anyone with some intuitions about the way views/windows/etc work could look at it for five seconds and know what's going wrong. One can always hope for the best.
I've been over and over the code, and I've tried countless permutations based on the documentation I've been able to find, but when it comes to views and that stuff, I don't even know what questions to ask. The GPU frame capture shows a perfect image on my pared-down Obj-C version, but it shows solid black on my Swift version, and I've not been able to find any reason for it. Putting out a call to view-friendly folks, cheers
Upvotes: 2
Views: 99
Reputation: 9829
Turns out you had nothing wrong with the view drawing stuff, and instead had some problems with working with UnsafeMutablePointer
.
In FoilRenderer.updateState
, you have this:
var u = uniforms.assumingMemoryBound(to: FoilUniforms.self).pointee
u.pointSize = FoilRenderer.bodyPointSize
u.mvpMatrix = projectionMatrix
Since FoilUniforms
is a value type, the pointee
property stores a copy of the value into u
. So when you change u
's pointSize
and mvpMatrix
, you're not actually changing the memory in uniforms
like you think you are. To fix this, assign the value back to pointee
:
var u = uniforms.assumingMemoryBound(to: FoilUniforms.self).pointee
u.pointSize = FoilRenderer.bodyPointSize
u.mvpMatrix = projectionMatrix
uniforms.assumingMemoryBound(to: FoilUniforms.self).pointee = u
In this case, since we're setting both pointSize
and mvpMatrix
(the only two properties of a FoilUniforms
struct), this can be simplified to the following:
let u = FoilUniforms(mvpMatrix: projectionMatrix,
pointSize: FoilRenderer.bodyPointSize)
uniforms.assumingMemoryBound(to: FoilUniforms.self).pointee = u
Similarly, you'll need to update a few places in FoilSimulation
for the same reason:
Change:
var c = c_.assumingMemoryBound(to: FoilSimParams.self).pointee
c.timestep = config.simInterval
c.damping = config.damping
c.softeningSqr = config.softeningSqr
c.numBodies = UInt32(config.numBodies)
to:
let c = FoilSimParams(timestep: config.simInterval,
damping: config.damping,
softeningSqr: config.softeningSqr,
numBodies: UInt32(config.numBodies))
c_.assumingMemoryBound(to: FoilSimParams.self).pointee = c
and change:
var p = positions[i]
p.x = position.x; p.y = position.x; p.z = position.z
p.w = 1
to:
var p = positions[i]
p.x = position.x; p.y = position.y; p.z = position.z
p.w = 1
positions[i] = p
(Notice there's also another unrelated error here, where you have p.y = position.x
– make sure to change that to p.y = position.y
or else you get some weird looking simulations!)
And then finally, change:
var v = velocities[i]
v.x = velocity.x * vscale
v.y = velocity.y * vscale
v.z = velocity.z * vscale
to:
var v = velocities[i]
v.x = velocity.x * vscale
v.y = velocity.y * vscale
v.z = velocity.z * vscale
velocities[i] = v
After making just those changes, I was able to get it to render properly:
Upvotes: 2