## Overview <img src="https://upload.wikimedia.org/wikipedia/commons/8/87/Apple_Metal_logo%2C_version_2.png" align="right" width="100" height="100" /> In 2014 apple decided to go against the flow yet again, instead of continuing to support opengl and embrace the new world of vulken, they decided on implementing their own graphics/compute API. This API is known as Metal. $\quad$While being in direct competition now with DirectX12(Microsoft) and Vulkan(KhronosGroup), Apple have been able to implement an impressive API that supports modern rendering techniques, and that performs in a similar capacity. $\quad$It is interesting to note **that both OpenGL and Vulkan are indirectly supported on Apple chips**, Vulkan is done so through [MoltenVK](https://github.com/KhronosGroup/MoltenVK). MoltenVK is portability implementation, and converts Vulkan API calls to Metal API calls. ## Prerequisites There are really two requirements in order to start writing applications using Metal... * An Apple machine(as of writing Ipads aren't supported dev-environments) * Latest version of XCode ## Using Metal for Graphics #todo > [!info] > I have no experience in using metal for graphics, this section will be updated in the future when I get round to it... > ## Using Metal for Compute Metal not only supports graphical operations but also compute operations. Implementing your own compute pipeline is in fact a lot simpler than I first thought it was. $\quad$There are a lot of similarities between Metal and the other API's. Basically, in order to trigger a workload you need to allocate a `commandBuffer` from a `commandQueue`. The allocated `commandBuffer` is then used to allocate a related `commandEncoder`. It is then the responsibility of the *encoder* to bind the resources etc, the *encoder* in this case is similar to a Vulkan `commandBuffer`. $\quad$In order to execute the compute program we need to end the encoding and call `commandBuffer.commit()`. I followed the youtube tutorial below in setting up and understanding how to get things going. <iframe width="560" height="315" src="https://www.youtube.com/embed/VQK28rRK6OU?si=GeAaIviqwuSHlFE_" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe> ### The Compute Shader To define a compute shader, create a `.metal` file and within it, depending on what it is used for you will either define the *main* as a `kernel`, `vertex`, `fragment`. In the tutorial above we write the following code: ``` c kernel void additionCompute(constant float *arr0 [[ buffer(0) ]], constant float *arr1 [[ buffer(1) ]], device float *resultArr [[ buffer(2) ]], uint index [[ thread_position_in_grid ]]) { resultArr[index] = arr0[index] + arr1[index]; } ``` $\quad$Shaders are then during build time compiled in XCode. The compiled shaders are then loaded into a library, and after which we are able to fetch the function *"pointer"* and use it to create a pipeline. See code below: ``` swift let device = MTLCreateSystemDefaultDevice()! let commandQueue = device.makeCommandQueue()! let lib = device.makeDefaultLibrary()! let subtractFunction = lib.makeFunction(name: "subtractCompute")! ``` $\quad$*Note: because the compiled shaders are loaded into a library, we are able to store multiple shader functions in one .metal file. As seen below!* ``` C kernel void additionCompute(constant float *arr0 [[ buffer(0) ]], constant float *arr1 [[ buffer(1) ]], device float *resultArr [[ buffer(2) ]], uint index [[ thread_position_in_grid ]]) { resultArr[index] = arr0[index] + arr1[index]; } kernel void subtractCompute(constant float *arr0 [[ buffer(0) ]], constant float *arr1 [[ buffer(1) ]], device float *resultArr [[ buffer(2) ]], uint index [[ thread_position_in_grid ]]) { resultArr[index] = arr0[index] - arr1[index]; } ``` #### Interesting Shader tools: * `function constants`: For more info read [[Function Constants and Übershaders]] ## Resources If you are interested in using Metal there are some resources that I could recommend * [Apple Documentation](https://developer.apple.com/metal/) ### GetIntoGameDev I regularly come back to *GetIntoGameDev*. He's is very thorough with explaining what is going on, and you can simply follow along with his implementatioon. <iframe width="560" height="315" src="https://www.youtube.com/embed/JjfIKllh6B8?si=sEXpp0ugxM4Hi7jH" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe> ### 2etime He seems to have stopped making youtube videos but he does have a series where he writes basic renderer using `swift` <iframe width="560" height="315" src="https://www.youtube.com/embed/videoseries?si=FQ3BbB4_kQ8SfNun&amp;list=PLEXt1-oJUa4BVgjZt9tK2MhV_DW7PVDsg" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>