Streaming is available in most browsers,
and in the Developer app.
-
Port advanced games to Apple platforms
Discover how simple it can be to reach players on Apple platforms worldwide. We'll show you how to evaluate your Windows executable on Apple silicon, start your game port with code samples, convert your shader code to Metal, and bring your game to Mac, iPhone, and iPad. Explore enhanced Metal tools that understand HLSL shaders to validate, debug, and profile your ported shaders on Metal.
Chapters
- 0:00 - Intro
- 2:06 - Evaluate your game
- 2:07 - Port your game
- 6:22 - Configuration
- 9:29 - Shaders
- 11:36 - Graphics
- 16:06 - Input and rumble
- 17:56 - Audio
- 18:53 - Cloud saves
- 21:28 - Debug and profile with Metal tools
- 28:39 - Wrap-up
Resources
- Download the Game Porting Toolkit 2
- Forum: Graphics & Games
- Get started with Metal shader converter
- Getting started with Metal-cpp
- Metal
- Metal Developer Resources
- Rendering reflections in real time using ray tracing
- Simplifying GPU Resource Management with Residency Sets
- Validating your app’s Metal API usage
- Validating your app’s Metal shader usage
Related Videos
WWDC24
WWDC23
- Bring your game to Mac, Part 2: Compile your shaders
- Bring your game to Mac, Part 3: Render with Metal
Tech Talks
WWDC22
WWDC21
- Discover geometry-aware audio with the Physical Audio Spatialization Engine (PHASE)
- Discover Metal debugging, profiling, and asset creation tools
WWDC20
WWDC19
-
Download
Hi! I’m Jacek Ratajewski, and I’m an engineering manager at GPU, Graphics, and Display Software group at Apple. Today, together with Alè, I will talk to you about how you can port your advanced games to Mac, iPad and iPhone.
Last year, Metal introduced the Game Porting Toolkit, that made it much easier to bring advanced games from other platforms to Mac. Games like "Death Stranding Director’s Cut", which was also brought to every iPad with an M-series chip and to iPhone 15 Pro. The new Game Porting Toolkit 2 brings an updated set of tools to accelerate porting your advanced games to Mac and to get them up and running on iPad and iPhone. First, if you already have your game running on Windows, you start your porting journey by using the included evaluation environment for Windows games to get a better idea how your game can run on Apple silicon. Next, you can leverage the human interface guidelines to help you apply design conventions that are specific to Apple devices. With the planning phases behind you, game porting example code provides a great starting point for setting up your project and learning about the best practices for porting your game. And if you are used to programming in C++, Metal-cpp gives you more freedom in choosing your preferred programming language.
If your game currently uses shaders implemented in HLSL, Metal shader converter helps bring them to Metal. And finally, if you rely on an existing asset building pipeline, Metal developer tools for Windows assist in leveraging it for your game on Apple devices. In this talk, we take you on the journey through the game porting process, which starts with evaluating your game. Next, we’ll show how the new Game Porting Toolkit can help you bring over your game’s code and assets... and finally, how you can leverage Metal tools on every step of the porting process to debug and profile your code. For the first step of your journey, if you already have your game running on other platforms, the evaluation environment for Windows games allows you to see your game running on Apple silicon before you even start the porting process. This can get you a better idea of baseline performance and confirm that your shaders convert successfully to Metal. Here's "Control" by 505 Games running on MacBook Pro through the evaluation environment.
This year’s updated version of the tool supports more game technologies. If your Windows game uses AVX instructions, you can now evaluate it before you start bringing it to Apple devices. The evaluation environment now also supports ray tracing and includes improved graphics and compute compatibility and increased performance so you can get an even better idea of how great your game will run on Apple devices.
And the new improvements to Metal tools within Xcode now enable you to debug and profile the source of your original HLSL shaders at any stage of the porting process, whether you’re evaluating your original Windows binary or debugging the Metal version of your game.
It’s also so exciting how the community has embraced the tool and provided additional ways to get started evaluating your existing games through projects like Whisky and Homebrew, or products like CrossOver.
Now, when people play your game on a Mac, iPad or iPhone, they may expect certain Apple platform conventions they are familiar with. To learn about what aspects of user experience to keep in mind while porting your game, check out the video "Design advanced games for Apple platforms". And the Game Porting Toolkit also has you covered with a new section of human interface guidelines specifically for games, including tips on topics like improving your first launch experience or ensuring your fonts are legible on all Apple display sizes. Now that you are ready to start porting your game, a good project configuration helps you target Mac, iPad and iPhone, and Game Porting Toolkit 2 provides you with amazing new sample code to help you accomplish this goal. The sample consists of an interactive tutorial taking you step-by-step through the main elements of the porting process.
The project layout organizes the documents into folders, each one providing concrete information on how to port your game’s subsystems, like graphics, shaders, audio, game controllers and many more. Each folder contains a lesson plus all code associated with it.
For example, if I open the folder for “GameInput”, Xcode reveals all files that handle game controller input in this project, and the README file includes all the information you need to understand how to bring game input support to your game.
It’s a great way to focus exactly on what you need, and have the code example right at your fingertips as you learn. Best of all, because it’s a full Xcode project, you can build and run it to see how it all comes together! This simple 2D game consists of all the code in all the chapters in this project and shows how all these technologies come together.
You can modify it, experiment with it, and even take parts of it for your own projects! And because it already includes all the configuration to target both macOS and iOS, you can just as easily build and run the game for iPhone or iPad. Using this sample code is a great start on the path to bringing your game to Apple devices.
Now over to Alè, so he can provide you with more details on how to port your game.
Thanks, Jacek. I’m Alè, an engineer from the Metal Games Ecosystem team here at Apple. Today I’ll walk you through some key areas of the game porting code example project. I start by showing you how to configure your projects to target both macOS and iOS; then, how to bring your shaders and graphics to Metal; input support, including rumble, audio; and finally, some tips on how to delight your players with a seamless, multi-device, gaming on-the-go experience via cloud saves.
Properly configuring your Xcode project sets you up for success in bringing your game to macOS and then building and running it in iOS in one step. With Xcode, it’s simple to target all Apple devices uniformly while still allowing for customization when needed.
This is great for games, as they typically use a common codebase and share most of their project settings across all destinations.
The game porting example shows you how to set up a multi-device project. The example targets both macOS and iOS devices. You can find this in project settings under "Supported Destinations". This setup ensures that both macOS and iOS can access the full capabilities of their respective SDKs.
When necessary, Xcode makes it easy to differentiate some elements like libraries, frameworks and parts of code, depending on the target.
Target conditionals for iOS and macOS help you compile parts of your files for one OS or the other.
Taking it further, your project may also contain whole files tailor-made for just one of the targets. For instance, app life cycle files may be separate for macOS and iOS. In this case, Xcode lets you use filters to specify files for a specific target, based on the SDK.
For your many shared files, however, just stick to an “Always Used” filter, to use them everywhere.
The majority of Apple frameworks you use for game development target both macOS and iOS. This makes the experience of developing for both really straightforward, and the new enhancements this year make it even easier.
Thanks to unified Metal shaders, you can now compile your shaders once and deploy them to both macOS and iOS.
Metal device initialization is also unified, so you can use the same creation API for both, and the device certification API lets you scale up and down your game’s configuration by querying devices for their performance profiles. Another enhancement this year is that Game Mode is now coming to iOS! When in Game Mode, iOS reduces background activity and also Bluetooth latency, improving input and headphone responsiveness.
iOS 18 may automatically enable Game Mode for your game but if you want to ensure you opt into it, just add “GCSupportsGameMode” key and set it to “true” in your iOS info.plist. The game porting example code demonstrates several of these key configuration steps, so please check it out to learn more. One more detail about the project configuration. C++ is a popular programming language in game development. You may already be using it in your game. To demonstrate how you can leverage your expertise in C++, the game porting example code comes preconfigured with Metal-cpp, our official C++ bindings for Metal.
This year, metal-cpp is now part of Game Porting Toolkit 2 If you’re already familiar with C++ syntax, it makes it easy to get started with Metal. Best of all, it has no measurable overhead compared to calling Metal Objective-C headers. To learn more, check out the documentation on developer.apple.com and the video from 2022. Now that you have your project set up, it’s time to bring your shaders.
Game Porting Toolkit 2 includes Metal shader converter. It makes it a joy to bring your shaders to Metal. It supports all shader stages, including cutting-edge ones like ray tracing and mesh shaders, as well as legacy technologies such as geometry and tessellation shaders. Metal shader converter really accelerates your porting timeline.
Ubisoft used the Metal shader converter in Game Porting Toolkit to bring the shaders from "Assassin’s Creed Mirage" to Metal, saving months of development time.
In addition to bringing your shaders, Metal shader converter also helps you port your resource layouts to Metal. And it includes a runtime header-only library that helps you bind resources to your pipelines and achieve common tasks. To learn more about Metal shader converter, please check out the documentation on developer.apple.com, as well as last year’s video "Bring your game to Mac, Part 2: Compile your shaders".
This year, Metal introduces globally-coherent texture access, and the updated Metal shader converter has full support for it. This allows you to develop advanced algorithms that require texture operations visible across all thread groups.
Additionally, because the Metal shader converter now understands and carries debug information from the source HLSL, you can now use the full power of Metal tools to debug and profile your converted shaders.
And finally, starting this year, you can convert your shaders to MetalIR once and deploy them across all Apple devices.
The game porting example project demonstrates how you can take advantage of Metal shader converter, and how to deploy unified shaders across both macOS and iOS after compiling them once.
You can invoke Metal shader converter from the command-line tool or by linking against its dynamic library, both on Windows and macOS.
The game sample uses the command-line tool for simplicity, directly passing the input file and specifying the output.
You can learn more about the rich set of options for shader conversion by running metal-shaderconverter --help.
With your shaders on the platform, you can start rendering graphics! For this, Metal offers a modern graphics and compute API that is designed and optimized for Apple devices. It provides a wide range of advanced features, so please check them out in the Metal documentation. This year, Metal brings improvements specifically designed for your games. First up, resource residency.
On other platforms, GPUs can have their own limited, separate memory. Games copy resources into them, and as long as they fit within the limited size, the game can access them efficiently. On the Apple platform, the unified memory model gives your GPU access to very large amounts of memory but you need to tell Metal which resources to make resident in order to access them.
To simplify this process and make it more familiar if you’re coming from other platforms, this year we're introducing Metal residency sets.
Your game loads its resources into the unified memory, which the CPU and GPU share. Residency sets allow you to define groups of resources and then make them resident all at once.
With residency sets, you don’t need to track individual resources anymore, which simplifies your code and helps reduce CPU overhead.
Using residency sets is easy. First, you create a new Metal residency set instance from your Metal device. You then add the residency set to a command queue. This automatically flags residency for everything in the set when you commit work to the queue.
You can also associate residency sets to individual command buffers.
Next, add the allocations that your game requires, like textures, buffers and even entire heaps.
Once you’re done, commit your changes to the residency set.
You do your setup step once, as you create or remove resources. At drawing time, you encode work as usual to a command buffer from the queue you associated the residency set to. Then, when you commit the command buffer, it inherits the residency set, making the allocations available to the GPU.
To learn more, check out the documentation and our updated "Rendering reflections in real time using ray tracing" code sample, as well as the game porting example code. Residency sets vastly simplify adopting Metal ray tracing, as you can now mark all your ray-traced scene resources resident as part of a set.
Metal also adds other improvements this year to help bring ray tracing from other platforms. You can now specify the transformation matrices in your acceleration structures in row-major order. This may save you from paying the cost of transposing them at runtime.
And direct access to on-chip intersection result storage improves performance by avoiding data copies and potential GPU memory spilling of passing arguments between ray tracing shader functions. Once your renderer produces beautiful images, you can use MetalFX to significantly improve the performance of your game. MetalFX works by scaling a lower resolution image up to the target output resolution in less time than it takes to render at the output resolution directly. Using MetalFX is easy.
In your render loop, after you create your temporal scaler object, you only need to specify your textures for color, depth, motion and upscaled output and also provide jitter offsets. This year, we are adding the new reactive mask. This optional feature may help you achieve higher upscaling fidelity in scenes that include fast-moving objects with inaccurate motion information, which may happen when using alpha blending.
Finally, encode the upscaling pass into the command buffer, and that’s it. Your temporal MetalFX upscaler is ready to go.
Metal offers many more advanced graphics and compute features than I can cover in this video. For a practical example of how to port your advanced renderer using Metal, check out the game porting example project as well as last year’s video, "Bring your game to Mac, Part 3: Render with Metal".
Programming GPUs is fun but for your players to see your beautiful worlds, you need to display them on screen.
The game porting example project shows how to use Apple frameworks to efficiently implement both full-screen and windowed modes for your game that adapt to the device’s geometry.
I also recommend you check out the video "Design advanced games for Apple platforms", which offers great guidelines for presenting your game to your players on Apple devices.
Games are more than just graphics. Porting other game subsystems is just as easy as rendering. Starting with input and rumble.
Input can take many forms.
Common to macOS and iOS devices, your game can sense and respond to player actions from game controllers, mice and keyboards.
Additionally, iOS devices recognize up to ten finger touches simultaneously, creating an even more personal experience.
The Game controller framework is a unified solution. Its modern and flexible design enables you to both register event callbacks and poll players’ actions on demand. It is the preferred method to get your player’s input on all devices.
The game porting example project shows you how easy it is to port your input code.
For example, if your current code directly polls game controller state, you may choose to also do that using the Game controller framework. The Game controller framework leads to shorter and cleaner code that is also safe to call even when your player hasn’t connected a game controller at all...
but input is only half the story when it comes to sensing. A big part of immersing your players is conveying feedback for in-game events with rumble.
You implement rumble using the Game controller framework in combination with Core Haptics. Core Haptics is the same framework you use to deliver tactile events on iOS devices with a Taptic Engine.
When a game controller supports haptics, you can directly create a haptic engine instance through its haptics property.
This single instance abstracts away any differences across game controllers from different vendors. For a deeper dive into the world of haptics, be sure to check out “Advancements in Game Controllers” and “Introducing Core Haptics”. When it comes to audio, Apple SDKs provide a comprehensive set of audio frameworks and technologies that are essential to creating a rich app experience. The PHASE framework, in particular, is excellent for games. PHASE is the Physical Audio Spatialization Engine. It can help you create rich, dynamic audio experiences for different kinds of output devices, like headphones or speakers. Even better, it can understand your game's scene, helping you simulate complex effects such as geometric sound occlusion. To learn more, check out the video introducing PHASE.
Your game’s logic may also integrate with middleware SDKs to play music and sound effects. If this is the case, popular middleware like Audiokinetic Wwise and FMOD are available for Apple devices. Check out the game porting example project, which uses PHASE to play back stereo sounds as the player shoots or objects collide in the game.
What makes your game stand apart on Apple devices is that, in addition to easily targeting both macOS and iOS, you can keep the game state synchronized across all your players’ devices.
For example, your player can start playing on a device at home. When they reach a milestone and save the game, you upload the game save data to iCloud. Then, say they catch a bus. No problem, they can open your game on their iPhone and pick up where they left off by loading game save data from iCloud and keeping it in sync as they play.
Finally, if your player goes to a café and decides to play on their iPad to use a larger screen, the game can load the progress from iCloud.
The key to continuing your progress on-the-go across devices is “cloud saves”. CloudKit helps you enable seamlessly switching between devices, making sure progress always counts. The game porting project shows how game save data from one device, such as high score, can make its way through iCloud to another device.
The sample provides a “CloudSaveManager" class that handles syncing for you.
To try it out, make sure to set it up using your iCloud identifier and specifying an existing folder containing game save data.
At game launch, the sample calls “sync”, passing a completion handler block. This block is a great place to handle any merge conflicts between local data and cloud data. Finally, to save progress to the cloud, the sample calls “upload” every time it writes into save files. This is another spot where you can pass a completion handler to resolve any conflicts. Now, playing across devices is great, but it wouldn’t be as satisfying if your progress didn’t unlock in-game achievements that you can boast to your friends about, and Game Center makes it easy to add these social features.
You create achievements through App Store Connect and associate them with your game. Each achievement has a unique identifier, and your game uses it to report your players' progress toward it. After you authenticate your player, you can use the “reportAchievements” function of class GKAchievement to report the new progress percentages.
Having your achievements in Game Center allows your player to continue to make progress towards them as they seamlessly switch from device to device.
Check out the game porting example code for more detailed steps on configuring your achievements with App Store Connect and reporting them to Game Center.
But writing code is not all there is to bringing your amazing games to Apple devices. I now hand it back to Jacek to tell you more about Metal tools. Thanks Alè! Metal offers an excellent suite of developer tools to help you debug and profile your ported game to make sure it can reach its maximum potential on Apple devices...
starting with runtime validation, which helps you catch common issues in both API usage and your shader code. The Metal Performance HUD provides an overlay for the real-time performance of your game. Metal debugger in Xcode offers advanced debugging and profiling workflows, such as analyzing dependencies, investigating visual artifacts, profiling shaders and many more! Lastly, Metal system trace in Instruments helps measure and analyze your game’s overall impact on the system.
New this year, you can use these debugging and profiling tools with your HLSL shaders that you brought to Metal with the Metal shader converter. There are 3 tools which I’d like to highlight for working with your converted shaders: runtime validation, shader debugger and shader profiler. But first, I'll show how to prepare your projects to provide these tools with sufficient debug information about your shaders. It only takes one step to prepare your shaders for debugging and profiling in Xcode. Add -Zi and -Qembed_debug as arguments for the DXC command. Then, Metal shader converter takes care of propagating the debug information to the Metal libraries.
After rebuilding your shaders with debug information, you’re ready to start debugging and profiling. The first runtime validation layer that Metal offers is API validation.
API validation protects you against invalid use of the Metal API, with checks for resource initializers, function arguments or unsupported functionality. It is extremely lightweight, so keep it enabled throughout the entire development process. And this year, validation is improved for Metal shader converter workflows, specifically for validating the state of samplers encoded in argument buffers. The Metal runtime validation also provides a second layer which is shader validation. Use it for catching bugs in your shaders, especially those that may introduce undefined behavior. Shader validation provides an address sanitizer, checks for invalid resource usage or residency issues, detects potential stack overflows, and it can now detect accessing textures with incorrect types. This is a common mistake when binding textures to converted shaders. Notice how in this case, shader validation, with its new validation check helped find an issue with a texture-type mismatch between the API side on the CPU and the shader side on the GPU, and it displayed the problem directly in your original shader code.
Advanced games may contain thousands of shaders, which is why this year, shader validation adds more control over which area of your shader code you want to validate. And you know your game best - so now you can enable or disable shader validation for selected pipelines depending on what you want to focus on. This may help reduce the noise from problems that are not relevant at the moment, or improve the performance of your game when shader validation is enabled.
To learn how to use API and shader validation layers, including per-pipeline validation, check out these articles in Metal documentation. Once you narrow down your problem to a specific pipeline, the shader debugger offers a unique and powerful set of capabilities when debugging your code. What makes the shader debugger special is that it displays all variable information for every line of code, all at once.
The debug navigator on the left shows the shader’s complete execution history. Selecting any line in the navigator highlights the line of code in the source editor.
The right side of the source editor shows previews for variable values. Clicking the preview button brings up a more detailed view for that particular variable, which shows its values for all neighboring pixels, while the mask on the right shows which pixels executed this line of code.
All this provides a really deep level of insight into your shaders’ execution and helps you debug even the most complex shader issues. Finally, there is the shader profiler, which is also receiving new support for your converted shaders. One approach to finding bottlenecks in your game is to identify the most expensive shaders and understand which are the most costly functions and lines of code.
For this, shader profiler provides the shader cost graph. The cost graph displays the most expensive shader function calls, with the corresponding shader source code below. The source code is annotated with performance statistics in the side bar on the left, indicating how expensive each line of code is. Hovering over the pie chart brings up the performance pop-over, which provides a detailed breakdown of that line of code, including the number of instructions that were executed on the GPU and the cost of different instruction categories. With this information, you can quickly hone in on the most expensive parts of your shaders. However, your shader’s performance may behave differently for different pixels on the screen. This may be caused by your shader executing divergent code paths or using distinct resources depending on the pixel location.
In these situations, the performance heat map helps you visualize the most expensive pixels. You can zoom in to inspect those pixels even more and see additional information for the SIMD group that the pixel is part of.
Selecting a pixel reveals the execution history for the SIMD group, which visualizes the call stack for all the threads, including the information about which of them were active at any point.
Below the execution history is the shader source code with performance annotations such as the number of instructions each line is executing.
These performance analysis workflows and other improvements to Metal shader tools bring the best tooling experience for your games, no matter if you rely on Metal shader converter or implement your shaders natively in Metal shading language. You can use all the Metal tools on every step of your porting journey - starting from evaluating your original windows binary, to porting, debugging and optimizing the Metal version of your game.
Learn about the full suite of Metal tools and find their documentation on the Apple developer website. Also, check out some previous videos for remarkable techniques to debug and further optimize your game.
Alè and I covered a lot of ground today, presenting many tools and platform enhancements to make your porting journey to Mac, iPad and iPhone a breeze. All these tools are available now, and we have a brand new landing page for Game Porting Toolkit 2 at developer.apple.com. You can access these tools individually, or download the unified package that contains everything you need to hit the ground running when porting your game. It’s never been easier to port your game to Mac, iPad and iPhone. All the new, and updated tools within the Game Porting Toolkit 2 provide you with support in each step of the process, including evaluation, bringing over your game’s code and assets, and adapting your game’s experience to Apple devices. And the new game porting example code is the best guide to help you along the way. Finally, with the improved Metal tools, it’s now much easier to debug and profile your game.
Download Game Porting Toolkit 2 and take it for a spin! And make sure to check out this year’s video "Design advanced games for Apple platforms". We can’t wait to see the next generation of games you bring to all Apple devices! Thanks for watching!
-
-
12:51 - Build a residency set
// Build a residency set. // Create a new residency set. MTL::ResidencySet* residencySet; residencySet = device->newResidencySet(residencySetDescriptor, &error); // Add to main command queue. commandQueue->addResidencySet(residencySet); // Add allocations and commit changes. residencySet->addAllocation(texture); residencySet->addAllocation(buffer); residencySet->addAllocation(heap); residencySet->commit(); // Use residency sets. // Allocate and encode a command buffer. MTL::CommandBuffer* commandBuffer = commandQueue->commandBuffer(); // ... // The command queue marks residency for the set for this command buffer. commandBuffer->commit();
-
14:46 - Upscale image with MetalFX
// Upscale image with MetalFX. mfxTemporalScaler->setColorTexture(currentFrameColor); mfxTemporalScaler->setDepthTexture(currentFrameDepth); mfxTemporalScaler->setMotionTexture(currentFrameMotion); mfxTemporalScaler->setOutputTexture(currentFrameUpscaledColor); mfxTemporalScaler->setJitterOffsetX(currentFrameJitter.x); mfxTemporalScaler->setJitterOffsetY(currentFrameJitter.y); mfxTemporalScaler->setReactiveMaskTexture(currentFrameReactiveMask); mfxTemporalScaler->encodeToCommandBuffer(commandBuffer);
-
19:53 - Use the cloud save manager
// Use the cloud save manager. CloudSaveManager* cloudSaveManager = [[CloudSaveManager alloc] initWithCloudIdentifier:@"iCloud.com.mycompany.mygame" saveDirectoryURL:[NSURL fileURLWithPath:@"/path/to/saves"]]; [cloudSaveManager syncWithCompletionHandler:^(BOOL conflictDetected, NSError *error) { // Handle conflicts or errors, for example, by presenting a choice. }]; // Access and write saves [cloudSaveManager uploadWithCompletionHandler:^(BOOL conflictDetected, NSError *error) { // Handle errors and conflicts or delay until the next sync. }];
-
-
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.