Metal in Mac Catalyst fails with texture in volatile state - ios

When using a texture with a purgeability state of volatile my app crashes with this error:
"MTLDebugCommandBuffer lockPurgeableObjects]:2103: failed assertion `MTLResource is in volatile or empty purgeable state at commit"
It works perfectly fine when I run the app by itself (not using the play button in Xcode but just clicking on the build icon) and also works when testing on iOS. This is a recent problem since updating to a newer version of Xcode recently. Is this something I can turn off so that the command buffers don't lock purgeable objects?

It's working as intended. Let me explain.
First, the fact that you are not seeing this problem in your app is due to the fact that by default, apps that are launched from Xcode run with Metal Validation Layer. This is an API layer that sits between an actual API and your app and verifies that all the objects are in a consistent state and meet all the required preconditions and such. Apps run outside of Xcode don't have this layer enabled by default, because doing all the validation has its cost that you don't want to pass to the users, because Metal Validation Layer exists to be used during development. You can learn more about it by typing man MetalValidation in your terminal. You can also run your app with Validation enabled without Xcode, by prepending the invocation from the terminal with MTL_DEBUG_LAYER=1.
The fact that the app is not actually crashing and seems to work fine without validation layer does not necessarily mean that it will work in every case and on every platform. Some drivers may be more strict, some less. That's why Validation Layer exists.
Second, let's address what the actual problem is. Purgable state exists so that Metal can have an option of discarding some resources when the memory pressure on the system gets too high, instead of jetsaming your app. Only those resources that are marked volatile can be discarded in such a way. But you can't just "set it and forget it". It's intended to be used for non-frequently used resources that are pretty big and can be discarded safely. The general pattern is described in this WWDC video starting at around min 39. Basically, if you are going to use a volatile resource, you need to make sure that it wasn't already discarded and also make it non-volatile. You need to explicitly call setPurgeableState with a nonVolatile state and check if it returns empty (setPurgeableState returns the state the resource was in before the call). If it does, then the resource was discarded and you need to re-generate or reload the resource. If it didn't, then the resource is still there. You can safely use it in a command buffer, for example, and then set it back to volatile in a completion handler.
I would suggest watching that part of the video, because it goes more in depth.
Also, refer to an article Reducing the Memory Footprint of Metal Apps
, WWDC video Debug GPU-side errors in Metal
and documentation page for setPurgableState

Related

Multiple nodes in .scn model causing iMessage extension to crash

I am working with SceneKit in an iMessage extension and have run into a peculiar little beast of an issue. I am trying to render a custom scn model and rig nodes to a users facial expression using blend shape anchors. I am able to do this succesfully in the iOS app that this iMessage extension is born from without an issue. However, once placed into a MessageViewController the program exits with code 0 every time I try to run it.
I did a bit of digging and it seems "exited with code 0" is indicative of memory overload so I started playing around with my models nodes. I discovered that if I delete all nodes but one, I am able to animate that node with its corresponding blend shape. Any more than one node and it crashes.
Does anyone have any ideas as to why this is happening? Or any proof that iMessage extensions are only granted a certain amount of processing power before they are killed off (another theory of mine)?
Appreciate any help!
from the App Extension Programming Guide we learn that
Memory limits for running app extensions are significantly lower than the memory limits imposed on a foreground app. On both platforms, the system may aggressively terminate extensions because users want to return to their main goal in the host app. Some extensions may have lower memory limits than others: For example, widgets must be especially efficient because users are likely to have several widgets open at the same time.
Your app extension doesn’t own the main run loop, so it’s crucial that you follow the established rules for good behavior in main run loops. For example, if your extension blocks the main run loop, it can create a bad user experience in another extension or app.
Keep in mind that the GPU is a shared resource in the system. App extensions do not get top priority for shared resources; for example, a Today widget that runs a graphics-intensive game might give users a bad experience. The system is likely to terminate such an extension because of memory pressure. Functionality that makes heavy use of system resources is appropriate for an app, not an app extension.
One option may be to try to optimize your geometry in your DCC so you don't run into system resource constraints.

Unique Realm container objects

I implemented real time sync following Realm's tasks demo app.
There a dummy container is used, to hold a List with the models.
The demo app doesn't seem to support offline usage.
I wondered what happens when, given this setup, I start the app on an online as well as an offline device and then go online with the offline device.
My initial expectation was that I'd end with 2 containers (which would be an invalid state), but when I tested surprisingly there was only 1 container at the end.
But sometimes I get 2 containers and haven't been able to identify what causes this.
The question then is, how does this exactly work? I assume the reason that the container is normally not duplicated when I sync the offline device for the first time is that it's handled as the same object, maybe because it doesn't have a primary key or something? But then why is it sometimes duplicated? And what would be the best practice here? Do I maybe have to use a primary key or check after connecting if there's duplication and if yes do a manual merge of the containers?
At the moment, Realm Tasks merely checks if the default Realm is empty before it tries to add a new base list container object. If the synchronization process hasn't completed by the time this check occurs, it's reasonable that a second container would be created. When testing the app on a local network, this usually isn't a problem since the download speeds are so fast, but we definitely should test this a bit more thoroughly.
Adding a primary key will definitely help since it means that if a second list is created locally, it will get merged with the version that comes down from the server.
We've recently been focusing on the 'on-boarding' process when a second device connects to a user's Realm Mobile Platform account via the new progress notification system. A more logical approach would be to wait for the synchronization to complete the initial download after logging in, and then checking for the presence of the objects. Once the documentation is complete, we'll most likely be revamping how Realm Tasks handles this.
The demo app (as well as the Realm Mobile Platform) does support offline, but only after the user has logged in for the first time (which is when these container objects are initially generated). After that time, the apps can be used offline, and any changes done in that interim are synchronized the next time it comes online.
We're planning on building 'anonymous user' feature where a user can start using the app straight away (even offline) and then any changes they made before they log in (due to them being offline) are then transferred to the user account after they do so.

When will my extern variable released using ARC?

I have a setup where all of my singletons' live in an extern NSDictionary (I need it globally visible, since I make many subclasses from a base singleton object with some common features).
Everything is fine, but on an iPad 1 running iOS 5.0, when user puts the application to background (not terminates, just press the home button), this dictionary gets released (so all of my singleton services, subclasses, etc.). The more interesting, they get recreated when I switch back to the application, but "sometimes" they're not, and my application behaviour gets unpredictable.
I've put __strong before the declaration, but it results in the same. It is quiet harmful when my singletons are destroyed/created all over the time, since they are storing runtime user/application states.
It is important that I'm debuggin with Fastest, Smallest Optimization Level to simulate production environment.
Is there any way to prevent this behaviour? To make/mark it "really retained" somehow?
So long as the application is "alive", they shouldn't be released, ever.
If your application is fully terminated (restarting simulator / closing it from the iPad), everything is released and when you open your app again you won't have anything.
Also, the point of a singleton is that you call a getter and it checks for its existence, and creates it if it doesn't, so there shouldn't be a problem if you don't have it at some point.
If you want persistent data when you re-launch your application, I suggest you look into serialization and/or some kind of persistence

Direct2D Direct3d11 interop - can device be lost?

In my app I'm using direct2d to write to a shared (d3d11/d3d10) texture. This is the only kind of render target that is used in my app. Since devices can be lost in direct2d (D2DERR_RECREATE_RENDER_TARGET), lots of code exists to abstract and/or recreate device dependent resources. However, I have yet to see this situation actually occur, and am curious whether I am wasting effort. Can the render target actually be lost in this scenario, or am I protected since the texture is created via d3d11 (though shared with d3d10)? If so, does anyone know a reproducible, simple way to cause the render target to be lost so I can at least test the code that handles this condition?
It’s not a wasted effort. Many scenarios may cause device loss to occur. A simple way to induce this for testing purposes is to update your graphics driver. Your application should handle this gracefully. It can also happen behind the scenes if your graphics driver crashes or Windows Update installs a new version in the background. There are other cases but those are probably the most common.
You can use the Device Manager to roll back and update your driver quickly.
A D2D window render target will always be lost when another program uses any version of the D3D API to go fullscreen and back (exclusive mode, not the new windowed mode supported since D3D10/11). In D3D11, I think you have to cause a resolution change for the D2D render target to be lost.
So if you do not get the D2DERR_RECREATE_RENDER_TARGET HRESULT in this case, when Presenting to your texture render target, then maybe you do not need to re-create the render target, but I would still handle D2DERR_RECREATE_RENDER_TARGET. To test it, you could just replace the texture render target with a window render target during development.

What actions are required when your app get an applicationWillResignActive call?

This question io3->ios4 upgrade said to support applicationWillResignActive. While implementing this call, I also implemented applicationDidEnterBackground and applicationWillEnterForeground. However, I found that my app would crash. After some debugging on the simulator I determined that I needed to reinitialize a key data structure in applicationWillEnterForeground. So my question is how would I have known that from reading the documentation? (In fact, I may be doing the wrong thing and just so happened to get it working again.) Is there an exact description of what to do when these methods are called?
Thanks.
The only things you should do when supporting multitasking, is saving the state of your app when it enters the background, and reload it when it becomes active. (If you generate a new template in Xcode, you'll see this.)
Saving state means writing any user preferences or data to disk. Reloading the state involves reading saved preferences and data, recreating any in memory data structures that might need it (like in your example you gave).
In most circumstances, there's little else you need to do. The only thing that would crash your app that is unique to multitasking would be trying to run code in the background for longer than the allotted amount of time, (which is 10 minutes.) Otherwise, it sounds like you have got other problems with your code.

Resources