How To Add Metal Shaders Into Playground (Since Playgrounds Don't Have Concepts Of Bridging Headers)

I have a C header file defining a struct to be used for the shaders but I can't figure out how to get playgrounds to recognize it. Any help is appreciated, thank you.

Replies

I've been trying to make a Metal playground too, and the only way I've gotten the compiler not to give issues on the struct definitions is to define the struct in a Swift file and then also define it in the Metal shader file - but I've also been having issues with my playground finding my shader file though in the MTLLibrary setup (see https://forums.developer.apple.com/message/352989#352989)

the only way I've gotten the compiler not to give issues on the struct definitions is to define the struct in a Swift file and then also define it in the Metal shader file

This is not recommended. The problem is that Swift does not provide you with a way to specify the layout of a struct. If you define a struct like this:

struct SharedWithMetal {
    var a: Int32
    var b: Int32
}

the Swift compiler is not required to place

a
at offset 0 in the structure and
b
at offset 4.

The standard way around this is to use a bridging header because a) C gives you some control over how structs are laid out, and b) if you import a struct from C, Swift will honour the layout used by C. This is problematic if you can’t use a bridging header.

The best way around this depends on what’s actually in your struct and how you’re using it. I generally run into this issue from the perspective of networking, and there it makes sense to add an explicit serialisation and deserialisation layer. I don’t have enough experience with Metal to know whether that’s a good option there.

If you decide to take the expedient path and use a Swift struct — which is understandable given the nature of these sorts of projects — I recommend that you add asserts that verify that the offset of each field is what you’d expect:

assert(MemoryLayout.offset(of: \SharedWithMetal.a) == 0)
assert(MemoryLayout.offset(of: \SharedWithMetal.b) == 4)

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

I really appreciate your detailed response! On a related question to this, should the Metal shader files go in the sources or resources of the playground?

Hey were you able to get this to work?

The structs for the shaders or getting the Swift code to find the shader file?

On a related question to this, should the Metal shader files go in the sources or resources of the playground?

Sorry, I don’t have any practical experience with Metal )-:

Oh, one other thing about structure sharing. When you take a pointer to a variable, Swift materialises that variable at a specific address for the duration that the pointer is valid. You have to be very careful about not holding on to that pointer for longer than that.

Consider this program:

func f(_ iPtr: UnsafePointer<Int>) {
    print(iPtr.pointee)
}

func main() {
    var i: Int = 42
    withUnsafePointer(to: &i) { iPtr in
        f(iPtr)
    }
}
iPtr
is only valid in the context of the body closure passed to
withUnsafePointer(to:_:)
.

Additionally, you can think of the

&
syntax as a shortcut for
withUnsafePointer(to:_:)
, so this is equivalent:
func main() {
    var i: Int = 42
    f(&i)
}

This matters when you deal with async code. If

f
starts as async operation which holds on to
iPtr
— that is,
f
returns to
main
while keeping a copy of
iPtr
— you will run into a World of Hurt™. When the async operation uses
iPtr
, there’s no guarantee it’s still valid.

As I mentioned above, I’m not a Metal expert, so I’m not sure how much of this applies to Metal. However, one of the goals of Metal is for the CPU and the GPU to run asynchronously with respect to each other, and another goal is to avoid unnecessary memory copies, and thus there’s certainly an opportunity to run into problems. Take care.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Since getting my playground to find the shader files has been preventing me from getting anything "real" to work, do you know where I'd be able to find out the answer to that question since you aren't familiar enough with Metal to answer that? And if not, that's fine - I've got an idea of what I'll do if I can't get a Metal implementation working for my playground.

do you know where I'd be able to find out the answer to that question

You could try starting a new thread in the Xcode > Playgrounds topic area. If that doesn’t pan out, you could try Graphics and Games > Metal. And then perhaps elsewhere on the ’net.

If all else fails you could ask DTS officially. I’m not sure if our Metal folks would take on a playgrounds question, but it wouldn’t hurt to ask.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"