Getting the Most Out of Simulator

Session 418 WWDC 2019

Join us for a deep dive into the world of Simulator. Find out how Simulator works, discover features you might not know exist, and get a tour of the command-line interface to Simulator for automation. Learn about native GPU acceleration in Simulator via Metal, and how to optimize your Metal code to take advantage of it.

[ Music ]

[ Applause ]

Good morning, everyone.

Welcome to Getting the Most out of Simulator.

My name is Russ Bishop.

I'm an engineer on the Simulator and Devices team.

And let's go ahead and get started.

Today we're going to tell you a little bit about what the Simulator is.

Then Tracy is going to come out and tell you about some burning questions and answers and getting the most out of the Simulator application.

I'm going to come back and tell you about using Simulator from the command line, and then finally Katelyn's going to come and tell you all about Metal in the Simulator.

So what is Simulator?

Well, it is the best way to simulate iOS, tvOS and watchOS devices on your Mac.

It can be an amazing tool for development.

Your Mac has more cores, more memory.

You can run multiple devices in parallel.

So it is a great tool, but as an engineer, that explanation might be a little bit unsatisfying.

So to talk really about what the Simulator is at a technical level, we need to talk a little bit about what an operating system is.

We have a kernel, manages hardware resources, allocates memory, arbitrates between processes.

That's pretty straightforward.

macOS then on top of that has a userspace.

We have PID 1, launchd.

We might have some daemons running on top of that, some services.

We have some frameworks, and then we run our applications.

Simulator is essentially a separate userspace.

It has its own launchd, its own daemons, its own frameworks and runs its own applications.

These things are all completely separate and isolated from your Mac's userspace.

And if I start another Simulator, that essentially brings up another isolated userspace.

It's isolated not only from the macOS userspace but also from any other running Simulators.

So at a technical level, what a Simulator is is the iOS, watchOS or tvOS userspace but running on the Mac kernel.

Has a separate launchd, separate daemons and services, separate notifications domains, separate URL sessions, separate mach bootstrap.

It does share the same filesystem but has a separate Home directory.

From libSystem up, everything is built for the platform that we're simulating, so that includes, at the lowest layers, you know, libSystem, all the Syslibs all the way up to UIKit and other frameworks.

It uses the ABI for that platform, and it's built natively for your Mac's processor.

It's not an emulator.

A couple of more details to cover.

The memory and CPU limits of Simulator are or rather, the memory and CPU limits of the devices are not simulated, so if your Mac has you have one of the new Mac Pros and you have a terabyte of memory, your simulator can allocate a terabyte of memory.

If you try that on an iPhone X, that probably isn't going to work.

Mac also has different number of cores, different threading behavior.

That can be a boon.

It can help expose data races or other threading conditions, but it is something to be aware of.

The application sandbox is not enforced, so a process in the Simulator can write outside of its sandbox, but, again, if you try that on the device, it's not going to work.

However, most people's Macs are setup with a case-insensitive file system, but the Simulator goes ahead and runs in a mode where all processes are using a case-sensitive file system accesses.

And then the, last but not least, the Thread Sanitizer is supported in the Simulator, whereas it's not supported on devices.

So that can be a useful tool.

So now, I'm going to hand this over to Tracy who's going to talk about some burning questions and answers.

Tracy?

[ Applause ]

Good morning.

My name is Tracy, and I work for the Development Technologies group.

So, you know, we often get questions in our session and in labs and through our user forums and via feedback.

So we thought it might be useful to go over the answers to some of those questions.

So my goal is that you'll walk away knowing at least one thing you didn't know before about the Simulator.

But to start off, I'd like to talk for a bit about why the Simulator should be important to your workflow.

Well, if we take into consideration all of the devices that are compatible with iOS 13, and then we add on all of the other operating systems and devices, you're looking at literally hundreds of devices and operating systems available to your customers.

And that's just the iPhones and the iPads, not even including the Watches and the TVs.

Well, that's a lot of stuff to be carrying around in your backpack.

And we thought about, "Well, what about testing with these older operating systems?"

So I'm sure you have customers that are using older devices and operating systems.

So you might be thinking, "Tracy, there's no way that I could test all these configurations."

Well, that might be true.

And although you may not have all these physical devices, through the Simulator, you will have access to every operating system and device available.

That makes the Simulator a very important tool to your everyday workflow.

All right, let's get on to those burning questions.

Number one, can I zoom in on the Simulator?

Yes, you can.

You can simulate the pinch gesture by click and dragging while holding down the Option key.

Another gesture you can simulate is drag and drop.

First, you grab the app.

Then you want to click down the Control key to simulate a hold, drag to where you want to go and then just let go of the Hold key.

Oh, that's a good one [laughs].

Next question.

Can I change which audio device the Simulator uses for input and output?

Yes, you can.

So that's done through the hardware menu.

You can select which audio device you want to route to.

That way you can listen to your Apple music without interruption.

Next question.

Does iCloud work in the Simulator?

Yes, it does.

You can log into iCloud through the Settings app, and then you'll have access to all your Calendars, Contacts and every other app that's available through iCloud and in the Simulator.

You can also trigger an iCloud sync by using the Debug menu, Trigger iCloud Sync.

Oh, look. I have a vacation coming up next week.

Good.

Next question.

Can I use a Shake Gesture?

Yes, you can.

In this example, a colleague created an app that will indicate when a shake is received.

So you go to the Hardware menu, and you select Shake Gesture.

You can also simulate a memory warning by going to the Debug menu.

Next question.

How do I get older simulators to show up as deployment targets?

So this is all done through the Devices and Simulator pane.

It's found under the Windows menu, or you can use the keyboard shortcut.

Xcode 11 now ships with a default list of simulators, which you may have noticed have been pared down quite a bit.

But you can always install additional simulators as needed.

How are we going to do that is we're going to go to the Simulators tab.

Next thing we're going to do is click on the Plus button at the bottom left.

Then you will select your device type and what operating system you want to use.

In this case, for the device type, let's select the iPad mini simulator.

Xcode 11 now ships with support for iPad minis going back to iPad mini 2.

So you're going to give this sim a name, and then you click Create.

And now your newly created simulator target will show up.

And you can run your app to the new iPad mini simulator.

Let's talk for a minute about Watch sims.

So preset Watch pairs are automatically added to the iPhone X and the Xs Max, but you can add a new pair by clicking on the Plus button.

Again, you'll select your operating system and device type, and then you click Pair.

So to change the act of pairs, all we do is click on the Radio button.

You can also download older simulator runtimes by going to the Xcode Preferences and selecting Components.

You can choose what you need and then click Install.

Older simulators will install, and then you will be able to select them based on the deployment target settings in your project.

You can also get older simulators by using the Hardware-Device menu, and they will just launch.

This will allow you to show newer operating systems and older operating systems side by side.

You can hide simulator targets by deselecting the Show as run destination.

You can also delete simulator targets if you don't want them around anymore, and you can use the Delete button on your keyboard.

Or you can use the Contextual menu, holding down the Control key.

You can also select these other items that are shown.

Remember, if you change your mind, you can always add a simulator target back again by creating them.

All right, let's go on to the next question.

The simulators are overtaking my screen.

Can I make them smaller?

Yes, you can.

So there are three presets that are available on the Simulator: Physical Size, Point Accurate and Pixel Accurate.

So what do these all mean?

Well, Physical Size is actually the physical size of the device.

You can hold up your device to the screen, and it will be the physical size.

Point Accurate is going to be one UIKit point will equal one AppKit point.

And then Pixel Accurate is the pixel-by-pixel representation based on your monitor resolution.

Or as some of you might know, you can always drag, open the Simulator and size it however you want.

So you can size it as large as your display.

Next question.

Can the Simulator help me debug UI animations?

Yes, it can.

So that's done through the Slow Animations under the Debug menu.

Once this is toggled and you select any app, it will go very slowly, slowing down the UI animations.

Next question.

Is Siri available in the Simulator?

Yes, it is.

As long as you give the Simulator access to your microphone, you can invoke Siri on all Simulator platforms.

Additionally, you can find Siri in the hardware menu, or you can use the keyboard shortcuts.

Next question.

How do I control my tvOS Simulator?

Well, there's a few different ways you can do this.

One is you can use the Apple TV software Remote.

So that's located under the Hardware menu.

Click on it.

And to activate the area, you just hold down the Option key while you move the cursor around.

Another way is you can actually use the hardware Apple TV Remote.

You pair it holding down the Plus and the Menu button on your remote, and then once it's paired, you'll be able to use the hardware Apple TV Remote on your tvOS Simulator.

You can also use game controllers, and for simple navigation, just use the keyboard.

Next question.

Can I use Xcode 10 with iOS 13 Simulators?

Yes, you can.

So as long as you have Xcode 10 running on the same system as Xcode 11-Beta, first thing you want to do is launch Xcode 11 and then also launch a Simulator.

So that'll give you an iOS 13 runtime.

Then you close down Xcode, but you leave the Simulator.app open.

Then you'll go into the older Xcode 10, bring it up, and then you can build and run to the Simulator.

Let me show you how that's done.

So this is we're running Xcode 10.

So what we're going to do is we're going to select the iOS 12.2 Sim, run our app to that.

And then we're going to change over to the iOS 13 Sim, and we're going to run our app to that.

Now you can look at the older and the newer side by side.

Oh, yay. That got a clap [laughs].

Next question.

Can I copy content into my Simulator?

There's a couple different ways to copy content.

One of the ways is through drag and drop.

So through drag and drop, you can copy app bundles, locations, photos and videos and URLs.

So in this example, I can take my project, grab my app bundle, just drag and drop it onto the Simulator.

It will install, and I can run it.

In this example, we're going to take some photos and videos.

So I grab them all, and I can just drag and drop them right into the Simulator, and they will automatically go into the Photos app.

Oh, wait. I drug in four, and I only got three.

Oh.

That's because the photo and video file are recombined to give you a live photo.

Drag and dropping URLs is simple.

Just open up Safari, grab the URL, drag and drop it.

And from within Safari, you can also use a Safari Share Sheet.

The Simulator is a target under the Safari Share Sheet.

Just select it.

It'll bring up a dialog.

You can select one simulator, or you can go to all simulators at the same time.

Also, you can share location via the Share Sheet.

At the Maps app, you got a location.

Just click the Simulator, select your target, and then it will share that location with the Sim.

OK, let's go over some other helpful hints that you might not have known.

Under the Hardware menu, there is the Rotate Device Automatically.

So if you toggle this setting, it will honor the settings in your project, and it will rotate the Sim automatically.

We have a few presets for simulator locations in the Sim.

One is like a freeway drive, so you can simulate a freeway drive.

You can also input your own custom location by putting in the longitude and the latitude.

If you want to see what your app will look like when a call is received, you can use the Toggle In-Call Status, or you can use the keyboard shortcut Command-Y.

External displays can be used for a variety of content.

In this example, what we're doing is we're playing some video out of Safari, and we're selecting a couple of different display resolutions.

Dark mode is also available on the Simulator.

You'll find that under the Developer menu.

Just go under Settings, toggle down to Developer, and you can click on Dark Appearance.

You can also change the wallpaper in your Sim if you want to.

You can just drag a photo into your Photos app.

Then click on the photo.

Use the Share Sheet, and that'll bring it up just like it does on the iOS device.

Select it as the wallpaper, and the Simulator will also use this as a wallpaper for your background, for the lock screen, and now you have a new background.

Dictation also works in the Sim.

So that's found under the Settings app.

You'll go under the keyboard, and there is an Enable Dictation.

So once you have that toggled on, you just bring up an app that accepts keyboard input.

Use Command-K to bring up the software keyboard, and then you'll see the microphone down there, and you just start dictating.

Input language can also be changed if you didn't know that.

So you can go into the keyboard, select what input language you would like.

There's a variety of languages in there available.

And then again, you're just going to bring up the software keyboard.

And you're going to click on the globe just like you do on your iOS device.

And speaking of keyboards, the new QuickPath is also supported in the Simulator.

Just open up the keyboard, start your path, and there you go.

You can find more information also by using the Simulator Help menu.

Type in what you need, and also the Search feature will just point you right where you need to go.

Well, my time is just about up, so I hope you learned at least one thing you didn't know before about the Simulator.

Now I'm going to turn it over to Russ who's going to go over running the Simulator through the command line.

Thank you.

[ Applause ]

Thank you, Tracy.

So let's talk a little bit about Simulator from the command line.

If I can leave you with one thing today, it'd be xcrun sim control or simctl.

But if I could leave you with two things today, it would be xcrun simctl help.

Sim control has extensive help.

If you run it without a command, it will tell you all of the commands that are available.

If you run help and then the command name, it will give you a lot more detail about that specific command.

So I'm going to cover a few commands that may be useful to you and then talk briefly about a few others, and then we'll do a little demo.

So the first command, the most basic command, is the list command.

This will show you the device types, runtimes, devices that you have.

I've shortened this list to fit on a slide.

You'll probably see quite a few more on your own machine.

We can see here that we have the device types, both their short names and their identifiers, the runtimes, short names and identifiers, my device, its identifier and then the current state, which is Shutdown.

Most of the commands that accept, for example, a device type or a runtime will accept the name, the short name.

It's totally fine to use that when you're typing at the terminal, save you a few keystrokes.

But I do recommend for automation and scripting that you go with the full identifier just to be specific.

The list command accepts a couple of different categories, one of which is devices.

So in this case, I'm not looking for the runtimes or the devices types.

I just want the devices.

I can specify that, and I can give a search string as well.

So in this case, I'm just looking at my iPhone X devices.

So list command also has a json flag.

This will output a machine-readable json file that you can use for automation purposes.

The next command I want to talk about is create command.

Some of you may have heard we have standalone Watch app support this year.

So I think I would like a standalone Watch simulator that I can deploy to.

So I'm going to call this Test Watch, and I'm going to specify the device that I would like, a Series 4 - 44mm.

And I would like that to be running watchOS 6.0.

The output will be the identifier of the device.

This is so I can capture that in an environment variable or use it for scripting purposes.

In this little example, I set NEW DEVICE to that value, and then, look the bot echoed the identifier, the device that was created.

Most Sim control commands follow the UNIX convention.

On success, they exit with zero.

On a failure, they exit with a non-zero code.

Errors are printed to standard error, and then actual output such as a device identifier or the json is output to standard out.

The next command I want to talk about is the spawn command.

The spawn command will pause xspawn a process inside the simulated environment.

And you might think, "What use is that?"

Well, we ship a couple of utilities in the Simulator that might be useful to you.

In this case, the default utility.

So I'm going to specify the device that I want to target.

In this case, I'm going to use the alias booted, because I have one booted simulator, so I don't need to actually specify which one it is.

And I'm going to say defaults write, the bundle ID of my application.

I want to set the ResetDatabase key to YES.

So this can be a handy way to change the user defaults for your application before it's running.

I can also run the log stream utility.

If you haven't seen this before or haven't run this on your Mac, you can pass a predicate, and you can stream the log output.

Well, you can do the same thing with the Simulator.

In this case, I'm going to say that the predicate is senderImagePath CONTAINS nsurlsessiond, because I want to debug something that's going wrong with my URL sessions.

And then I can see the log stream output.

You may notice sim control has detected that I'm using an interactive terminal that supports color.

It's passed that information through, so log stream is giving me some nice pretty colorized output.

And here I can see my dataTaskWithRequest allowsCellularAccess is set to 1.

That's what I expected, so I'm happy.

Speaking of logs, the next command I want to talk to you about is diagnose.

This is an incredibly useful command.

The diagnose command will go through and collect not just logs on disk, but ephemeral logging and dump system state that can be useful in tracking down a problem.

This a great thing to run in automated systems if you have a test failure or some kind of issue immediately capture diagnose, control diagnose.

This is also great if you're filing bugs.

So in an automated scenario, I'm going to pass the -l flag to skip the privacy warning.

But I do recommend that you read that before you use this command and also check out Apple's privacy policy.

This will tell you the types of information that this will collect, could include account names and things like that.

The diagnose can run.

It'll tell me where it wrote the file to.

If I'm using this at my desk, I would also get a Finder window that pops up, that shows me the file it produced.

So, please, if you're going to send in feedback through the new Feedback Assistant with issues occurring the Simulator, attach a sim control diagnose.

That makes it much easier to figure out what went wrong.

And I do recommend you use it in your own workflows if you're going to send a bug to For example, if you're working in QA, you're going to send a bug to the engineer.

Hey, the app something went wrong.

Attach a diagnose.

That'll include all the log output from your application.

The next command that I want to tell you about is launch command.

Launch command launches an application.

You might ask, "Well, what is difference between that and spawn?"

Well, launch politely asks the system, "Would you please start the application with this bundle ID?"

This is equivalent to tapping on the icon on the Home screen.

And in fact, this is the only way a process can display information on the screen on iOS, watchOS or tvOS.

So it's incredibly important.

So if you actually want to launch an installed application, you'd need to use the launch command.

So I'm going to specify again the booted alias, because I only have one simulator that's booted.

I'm going to launch my com.apple.example application, and I'm going to pass some arguments.

If you haven't seen this before, user defaults allows you to override defaults that you've set as arguments from the command line.

Prefix the key with a single dash, the key name and then specify the value.

And for that specific launch of my application, the -MyDefaultKey will be set to YES regardless of what's stored on disk.

The launch can do something else very interesting for me.

If I pass the console-pty flag, launch will connect my application's standard input, output and standard error to the terminal I'm working with right now.

So when I launch this application, I see its standard output right there in my terminal.

And more than that, I can hook up debugging facilities.

In this example, I press Enter, and it's going to dump some debugging state.

So in Terminal, I can press Enter, and I get that debugging state printed from the application.

This can be a real useful tool when you're debugging.

The other thing you might notice is I press Control-C, which sends an interrupt signal.

Sim control detects that, grabs the signal and passes it through to the application.

That applies not just to signals like interrupt, but user signals: user1, user2.

Those are other ways you can set up your application to include debugging information.

So there's a couple more commands that I don't have time to go into, but I'm just going to briefly give you an overview.

Boot as you might expect boots a device.

Shutdown also pretty obvious; it shuts down the device.

But shutdown accepts a special alias.

The all alias That will just shut down all running simulators.

Delete, again as you might expect it deletes a device.

But there's another convenient alias that it accepts unavailable.

That will go through and find all of the simulators that use a runtime that's not available to you anymore.

Maybe it's an older version of Xcode that you've upgraded or it's a downloaded Simulator runtime like Tracy showed you that you've deleted.

That will go through and clean all these up and recover that disk space.

The next one, pair.

There's pair and also an associated unpair and pair activate.

You can set up watch phone pairings from the command line.

Addmedia that's similar to what Tracy showed you earlier dragging, dropping photo and media into the Simulator.

You can script that as well.

Get app container is an interesting one.

If something's going wrong with your app.

Perhaps it's writing a corrupted file or it's attempting to load something, and you know it should be there, but it's not there, get app container can give you the path on disk to your application's data container or even to a shared container that perhaps your app and your app's extension are using.

And you can go then examine the actual content, the filesystem from Finder or from Terminal and see what's going wrong.

Install. Again, that's very similar to what Tracy showed you with dragging dropping app bundle.

You can install an application from the command line.

And then the last one I want to mention is the io command.

Io itself has several subcommands, probably the most important of which is screenshot.

So that allows you to automate taking of screenshots in Simulator.

And then the last command I want to talk about is the clone command.

Clone is a very powerful command that can be used for automation, for testing, for making experiments.

Clone allows you to set up a single simulator exactly how you want, install your app, set user defaults, load data.

Then you can shut that simulator down and then make as many copies of it as you want.

Then you can run those copies, perform your experiments and then throw them away when you're done.

This can be a great timesaver and saves a lot of disk space because clone takes advantage of APSF file cloning under the covers.

If your game has a gigabyte worth of assets and you want to run multiple tests in parallel, you can go ahead and do that without taking up a bunch of disk space.

So rather than talk more about that, I'm going to show you with a demo.

OK.

So the first thing that I'm going to do is I'm going to go ahead and start the simulator that I'm going to use as my sort of baseline for comparison.

So I'm going to start that simulator.

You can see I have the Simulator app open, so it automatically attaches to it.

The next thing I'm going to do is install my application.

I have my application bundle here and ready to go.

So like I showed you earlier, I'm going to run install, booted in that application.

Well, see, it appeared on the Home screen, and it's now installed.

So the next thing I'm going to go ahead and do is shut this simulator down.

We do need to shut it down before we can clone it.

And then once I've shut it down, I'm going to go ahead and create a clone called clone-1.

And now I'm going to run this command again.

I'm going to create another clone, clone-2.

Now that I have these two clone simulators, I'm going to go ahead and ask them to boot.

And here we can see that both of them are starting up.

They started up much more quickly, because I don't have to pay the first boot cost.

I already paid that cost with the base simulator when I set it up.

So that can be a great timesaver.

And then here's what I could set up things in place for my demos or my experiments that I want to run, and then I would launch the application on both of these simulators.

Now, some of you may actually recognize this code.

This is the Metal DeferredLighting demo.

This is something that we weren't able to run in previous years.

This is new to Xcode 11 when running on macOS Catalina.

And to tell you all about Metal in the Simulator, I'm going to invite Katelyn out.

Katelyn?

[ Applause ]

Thank you.

Thank you, Russ.

Good morning.

I'm Katelyn Hicks, and I'm an engineer on the GPU Software team.

And today, I'm excited to tell you about the new Metal support in Simulator.

So let's dive in to see how to get the most out of Metal in Simulator.

While running on macOS Catalina and Xcode 11, Simulator now supports Metal.

But what does that mean for your application?

Well, two things.

Simulator is fully GPU accelerated for all applications.

And second, the Metal API is now available to use in Simulator.

So let's take a look at how fast Simulator is while running on macOS Catalina and Xcode 11.

We'll quickly go through a few applications to see that, across the system, animations are much smoother, and user experience is more responsive.

This is due to the fact that Apple frameworks have migrated to Metal renderers and are now taking advantage of the GPU.

So if your application is not using Metal, but instead you're using an Apple framework for UI 2D or 3D graphics, you will still get the performance improvements of GPU acceleration.

There are no changes necessary for your application to achieve GPU acceleration through Metal.

This speedup is free.

Now, I'd like to show you a few examples.

So on the left, we have a device that is running on the software renderer.

And on the right, we have the newly GPU accelerated simulator.

In this simple graphics workload, we can see the improved performance through scrolling through this Table View that uses UIKit.

Since the original Simulator, an iOS device's resolution has increased 17 times, which has put extra pressure on the underlying software renderer.

In this SpriteKit Xcode template, we see the performance dipped down to 15 frames per second in the software renderer, whereas we're rendering the same application in Xcode 11 and macOS Catalina, and we see a steady 60 frames per second with more SpriteKit nodes rendering in the scene.

For more complex 3D scenes like this Fox demo that uses SceneKit, we see a dramatic performance improvement without any changes to the Fox application source.

And now it is possible to run multiple simulator devices in parallel with real-time performance.

In this Badger demo, which also uses SceneKit, the geometry and animation was previously too strenuous for a single software rendered GL simulator device, let alone two running in parallel.

For those of you that use Metal directly, Metal development is now possible, and the workload is fully accelerated.

Let's see how your experience has changed while running your application in Simulator.

So previously, you may have seen a black screen.

But now when you run your application in Simulator, you'll be able to run your application across all simulated devices.

Now that you've seen it in action, let's dive into more details.

If you've seen our other Metal session, you know that this year we have revamped our feature query API and have introduced the Metal GPU Family API.

The Metal GPU Family API makes writing cross platform code simpler by abstracting GPU capabilities into a few distinct tiers, and the three families that are relevant to Simulator are first common, which includes all GPU features that are available cross platform.

And second, macOS, which in includes the features that are specific to macOS GPU hardware.

And third, Apple, which includes the features that are specific to iOS and tvOS GPU hardware.

So while running your application in Simulator, your application can use features from MTLGPUFamilyApple2, which includes features that are included in MTLGPUFamilyCommon1 as well.

This support is common for all Simulator devices.

So let's take a look how it is possible to run your iOS application in Simulator.

Previously, your application rendered on an OpenGL ES software renderer for all applications, and it had no GPU hardware acceleration.

But now in Xcode 11 and macOS Catalina, the great news is the Metal API is available to use in Simulator.

And all of the Apple frameworks are now using Metal as well.

But not only it is available, it's GPU-accelerated.

So this means that all commands that are created by your iOS application for UI 2D or 3D graphics are all being translated from iOS Metal to macOS Metal.

And this translation allows you to take advantage of the underlying Mac GPU on your system.

But this does come with a few caveats and one of them being the performance you see may be different from the actual device.

So the graphics you see will be the performance of your underlying Mac GPU.

And the Simulator device is not a true iOS GPU emulator.

So if you run an iPhone success simulator on your incredibly fast Mac Pro, the performance you see will be different from running your application on an actual success device.

So as always, make sure to profile and optimize your application directly on devices before shipping your application.

One other thing you need to take into mind is the fact that there are different storage modes across macOS and iOS.

iOS has support for private, shared and memoryless textures, whereas Mac has support for private and managed textures.

And while the native macOS device does not support shared and memoryless textures, they are supported in Simulator.

There are a few other special cases with shared storage, but first let's revisit how shared storage works.

So when you create an iOS texture with Shared Storage mode, this means that your texture can be modified both on the CPU and on the GPU.

And so if your application wanted to initialize this texture on the CPU, then bind your texture to a render or compute encoder to be read on the GPU.

You could directly modify this same texture on the GPU and then read back those modifications on the CPU after the command buffer completes.

And your app does not have to worry about any memory synchronization as on iOS it's a unified memory model.

And so in Simulator, for multisampled, depth stencil and linear textures, these texture types must be created in private storage, whereas on an actual iOS device, these types may be in shared storage.

And so your app may need a simulator-only path if you need CPU access to these textures.

For most of you, you will initialize these texture types and use them directly in your GPU commands, and so this won't affect your application.

They should already be private textures.

But if you do need CPU access for one of these textures, let's go through what changes may be required.

So as a reminder, if you create a texture in private memory, the texture does not have CPU access.

It only can be modified by the GPU and read by the GPU.

So if your app reads or writes to the texture on the CPU, you need an intermediate shared resource to do so.

So first we can either create a shared buffer or a shared texture.

Then in order to copy this texture, you create a BlitCommandEncoder, and you can copy from the shared buffer in this case to the private texture.

Or you can copy from the private texture to the shared buffer.

So let's take a look at what this looks like in source code.

So in this code example, we see that a depth stencil texture is created, and we want to initialize it on the CPU.

So first, we set the storage mode to private only in Simulator.

While we're not in a simulated environment, we want to still use a shared storage mode.

Then we create the texture with the modified textureDescriptor.

And then while in the simulated environment, in order to initialize this private texture, we will first create a shared buffer.

For this shared buffer, we will initialize it on the CPU with the data that you'd like to see in your private texture.

And finally, we blit from that shared resource to the private texture.

And then in the case that you're still running on an actual iOS device, we want to do the exact same thing you did before and initialize that texture on the CPU and avoid this unnecessary blit.

From this point forward, the use of this texture is the exact same, whether you're running on an actual iOS device or in the Simulator.

All of your GPU commands can be the exact same.

And so there are a few other changes that may be needed for your application in Simulator, and for that we have full documentation for those small changes.

And we also have a sample code available for you to download and to see example of porting an application to Simulator.

I hope you learned something new about Simulator today.

We first went over that the iOS, watchOS and tvOS userspace is running on the macOS kernel and that the Simulator is pivotal to testing your application across all devices and runtimes.

We saw the power of xcrun simctl and how you can script all of your testing through Simulator.

And lastly, we saw that the GPU acceleration through Metal in Simulator is for everyone, and it also enables Metal development in the Simulator.

And if you have any other questions, please visit the session website.

Thank you, and I hope a great rest of your week.

[ Applause ]

Apple, Inc. AAPL
1 Infinite Loop Cupertino CA 95014 US