Can Vertex Array Objects (VAOs) be shared across EAGLContexts in OpenGL ES? - objective-c

Spoiler: I'm fairly confident that the answer is NO, but that's only after a day of very frustrated debugging. Now I would like to know if that is indeed the case (and if so, how I might have known), or if I'm just doing something completely wrong.
Here's the situation. I'm using OpenGL ES 2.0 to render some meshes that I load from various files (.obj, .md2, etc.). For the sake of performance and User Experience, I delegate the actual loading of these meshes and their associated textures to a background thread using GCD.
Per Apple's instructions, on each background thread, I create and set a new EAGLContext with the same shareGroup as the main rendering context. This allows OpenGL objects, like texture and buffer objects, that were created on the background thread to be immediately used by the context on the main thread.
This has been working out splendidly. Now, I recently learned about Vertex Array Objects as a way to cache the OpenGL state associated with rendering the contents of certain buffers. It looks nice, and reduces the boilerplate state checking and setting code required to render each mesh. On top of it all, Apple also recommends using them in their Best Practices for Working with Vertex Data guide.
But I was having serious issues getting the VAOs to work for me at all. Like I do with all loading, I would load the mesh from a file into memory on a background thread, and then generate all associated OpenGL objects. Without fail, the first time I tried to call glDrawElements() using a VAO, the app crashes with EXC_BAD_ACCESS. Without the VAO, it renders fine.
Debugging EXC_BAD_ACCESS is a pain, especially when NSZombies won't help (which they obviously won't), but after some time of analyzing captured OpenGL frames, I realized that, while the creation of the VAO on the background thread went fine (no GL_ERROR, and a non-zero id), when the time came to bind to the VAO on the main thread, I would get a GL_INVALID_OPERATION, which the docs state will happen when attempting to bind to a non-existent VAO. And sure enough, when looking at all the objects in the current context at the time of rendering, there isn't a single VAO to be seen, but all of the VBOs that were generated with the VAO AT THE SAME TIME are present. If I load the VAO on the main thread it works fine. Very frustrating.
I distilled the loading code to a more atomic form:
- (void)generate {
glGenVertexArraysOES(1, &_vao);
glBindVertexArrayOES(_vao);
_vbos = malloc(sizeof(GLuint) * 4);
glGenBuffers(4, vbos);
}
When the above is executed on a background thread, with a valid EAGLContext with the same shareGroupas the main context, the main context will have 4 VBOs, but no VAO. If I execute it on the main thread, with the main context, it will have 4 VBOs, and the VAO. This leads me to the conclusion that there is some weird exception to the object-sharing nature of EAGLContexts when dealing with VAOs. If that were actually the case, I would have really expected the Apple docs to note that somewhere. It's very inconvenient to have to discover little tidbits like that by hand. Is this the case, or am I missing something?

According to this, OpenGL-ES explicitly disallows sharing of VAO objects:
Should vertex array objects be sharable across multiple OpenGL ES
contexts?
RESOLVED: No. The OpenGL ES working group took a straw-poll and
agreed that compatibility with OpenGL and ease of implementation
were more important than creating the first non-shared named object
in OpenGL ES.
As you noted, VBOs are still shareable, so you just have to create a VAO for each context that binds the shared VBO.

Related

Objective-C atomic operations/locking access to myLocation property in Google Maps iOS SDK

This is partly a question regarding the Google Maps SDK in iOS, though perhaps mostly a question about atomic operations in Objective-C.
In my app, I wish to draw a GMSPolyline on a map between the user's current location and a selected destination. I can retrieve the user's current location using the myLocation property on a GMSMapView. According to the documentation for myLocation:
If My Location is enabled, reveals where the user location dot is
being drawn.
If it is disabled, or it is enabled but no location data is available,
this will be nil. This property is observable using KVO.
I have code to draw the polyline which takes the form:
if (myMapView.myLocation) {
// draw polyline between myMapView.myLocation and the selected destination
}
My concern is that, however remote the possibility, that between the check if (myMapView.myLocation) and drawing the polyline // draw polyline between myMapView.myLocation and the selected destination, myMapView.myLocation might become nil if the location is lost at an inopportune moment.
So my question is, in Objective-C, is there a way for me to wrap both the check that myMapView.myLocation is not nil and drawing the polyline into an operation which locks access to myMapView.myLocation, so it can't be changed after the check but before attempting to draw the polyline. If Objective-C does provide a mechanism, what affect does this have if the Google library does attempt to update myLocation while it is locked? Does the update just get queued until I've finished drawing the polyline and release the lock?
So I guess this is mostly a question about atomic transactions in Objective-C, in the context of the Google Maps library.
I don't know specifically for Objective C, but based on locking in other languages, I think what you want could only work if it was done in cooperation with the third-party library (ie Google Maps).
So for example if you were to somehow lock myMapView.myLocation while using it, this would only work if the Google Maps SDK also promised to lock it while modifying it, with the same lock object that you are using. Since myMapView.myLocation can be nil, this would be unlikely to work since you couldn't use a nil object as the 'key' to lock.
Similarly if you could lock the entire GMSMapView, such that none of its properties could change while the lock was held, this could only work if the Google Maps SDK promised to take the same lock before making any modifications.
In general, it's probably not a good idea to lock arbitrary objects from third-party libraries, as this might interfere with that library's own synchronization (unless the library explicitly offers this as part of its interface). Vice versa, when writing a library for use by third parties, it's best not to implement internal locking on objects which the library makes public - instead locking should usually be implementated on internal objects - just in case a user of the library tries to lock the public object.
In your case though, you could avoid the problem by doing this:
CLLocation* location = myMapView.myLocation;
if (location)
{
// draw polyline between location and the selected destination
}
That way even if the map view sets its .myLocation property to nil in between your check and your draw, you will still have a reference to the CLLocation, which can't be set to nil.
Note though that the documentation says:
GMSMapView can only be read and modified from the main thread, similar
to all UIKit objects. Calling these methods from another thread will
result in an exception or undefined behavior.
It seems likely that GMSMapView would honour the same requirement and so only modify its public properties from the main thread. So if your code is running in the main thread (which it has to), its unlikely that the map view's properties will change in the middle of your code running.

iOS6 and ACAccount: Twitter type disappears?

I try to authenticate my app with Twitter with following code: pastebin
However, if I remove the (useless?) loop line 23ff
for (ACAccount *acc in arrayOfAccounts) {
[acc accountType].identifier;
//Otherwise the identifier get lost - god knows why -__-
}
the acc.type becomes (null) when it gets executed further in
AccountHandler checkAccountOf:acc. If I leave the loop in, the type is correctly set.
I am pretty sure it has to do with the fact that I am in a block and then move on to the main queue, but I am wondering if I am doing something wrong? This loop does not look like sth I am supposed to have to do.
Something kinda similar happened here.
ACAccounts are not thread safe. You should use them only on the thread that they originate. And for this purpose you can read 'thread' as 'queue'.
While I've not seen formal documentation of that, if you NSLog an account you'll see that it's a Core Data object and the lack of thread safety on Core Data objects is well documented.
The specific behaviour is that a Core Data object can be a fault. That means that what you're holding is a reference to the object but not the actual object. When you try to access a property the object will be loaded into memory.
What Core Data is doing underneath is caching things in memory and returning faults until it knows that an object is really needed. The efficient coordination of that cache is what limits individual instances of the Core Data object that coordinates objects to a single thread.
If you do the action that should bring the object into memory on the wrong thread — which is what happens when you access identifier here — then the behaviour is undefined. You could just get a nil result or you could crash your application.
(aside: the reason that Core Data works like this is that it stores an object graph, so possibly 1000s of interconnected objects, and you can traverse it just like any other group of objects. However you don't normally want to pay the costs associated with loading every single one of them into memory just to access whatever usually tiny subset of information you're going to use, so it needs a way of providing a normal Objective-C interface while lazily loading)
The code you've linked to skirts around that issue by ensuring that the objects are in the cache, and hence in memory, before queue hopping. So the 'fetch from store' step occurs on the correct queue. However the code is nevertheless entirely unsafe because objects may transition from being in memory back to being faults according to whatever logic Core Data cares to apply.
The author obviously thinks they've found some bug on Apple's part. They haven't, they've merely decided to assume something is thread safe when it isn't and have then found a way of relying on undefined behaviour that happened to work in their tests.
Moral of the story: keep the accounts themselves on a single thread. If you want to do some processing with the properties of an account then collect the relevant properties themselves as fundamental Foundation objects and post those off.

Is it safe to use managed objects loaded in background by performBlock: in main thread?

I'm creating my managed object context with NSPrivateQueueConcurrencyType concurrency type.
Also I'm using performBlock: selector to execute operations in background. So If I'm fetching some objects in background (in performBlock:), is it safe to use resulting managed objects in main thread?
As a general rule, no it is not safe to share NSManagedObject instances across threads no matter what concurrency type you are using.
However there is a library you can use to make your context(s) and object instances thread-safe. With that you can pretty much ignore all the nonsense about ensuring thread isolation between contexts and focus your efforts on the things that matter, like building out the actual functionality of your app.
I'm not 100% sure, but in my own experience I do it this way: If you are changing the variables properties, do it inside performBlock. I had one case where reading was causing some weird behavior, but in general it seems to be OK. If you want to be extra safe, use performBlock every time you touch a managed object in any way.
You will need to use a different context for each thread as explained here iOS Developer - Core data multithreading
One way to implement is described at Core Data - one context per thread implementation
Sorry, I should've search better, here is exactly my question & answer to it:
Core Data's NSPrivateQueueConcurrencyType and sharing objects between threads

Thread safety of UIImage

I know that Apple officially recommends UIKit to be used in the main thread only. However, I've also heard claims that UIImage is thread-safe since iOS 4.0. I cannot find any documentation backing this claim.
Does anyone have any information to support this claim? As a class used to store data and decode image data, UIImage should be thread-safe if well designed.
Directly from Apple's documentation for UIImage
Image objects are immutable, so you cannot change their properties after creation. This means that you generally specify an image’s properties at initialization time or rely on the image’s metadata to provide the property value. It also means that image objects are themselves safe to use from any thread. The way you change the properties of an existing image object is to use one of the available convenience methods to create a copy of the image but with the custom value you want.
(Emphasis mine)
So at least in the current version of the SDK as of May 13, 2014, "image objects are themselves safe to use from any thread."
It is true that apple recommends using elements from the UIKIt on the main thread:
Note: For the most part, UIKit classes should be used only from an
application’s main thread. This is particularly true for classes
derived from UIResponder or that involve manipulating your
application’s user interface in any way.
Since UIImage isn't derived from UIResponder, and you do not actually display it on the interface/screen. Then doing operations with UIImages on another thread should be safe.
This is however based on my experience, I haven't seen any official documentation about it.
It looks like Apple have updated their documentation since the earlier answers here were posted. According to the most up-to-date documentation, it is safe to create and use UIImage instances from any thread:
Because image objects are immutable, you cannot change their
properties after creation. Most image properties are set automatically
using metadata in the accompanying image file or image data. The
immutable nature of image objects also means that they are safe to
create and use from any thread.
https://developer.apple.com/reference/uikit/uiimage
In the What's New in iOS: iOS 4.0 release notes, the UIKit Framework enhancements include this bit:
Drawing to a graphics context in UIKit is now thread-safe.
Specifically: The routines used to access and manipulate the graphics
context can now correctly handle contexts residing on different
threads. String and image drawing is now thread-safe. Using color and
font objects in multiple threads is now safe to do.
So UIImage is thread-safe on iOS 4.0 and later.
Just to make it short:
UIImage is not thread safe, or better does only work on the main thread,
as I have experienced in my current after some debugging.
I hope that helps.
I wish to have more clarity about this from Apple
or even better an UIImage class, that could be rendered in a different thread.
Shouldn't be too difficult ...
edit:
After some research, I found that it is "UIGraphicsGetImageFromCurrentImageContext();"
that causes the trouble.
it's a bit off the topic, but maybe this helps:
https://coderwall.com/p/9j5dca
Thanks to Zachary Waldowski.
Thread-safe is not the issue, in that any thread can attempt to access a context at the same time (concurrently). And, while that is generally okay, in low-memory situations, like with a Photo Editing Extension on iOS devices, two threads accessing one context can crash an app due to low memory.
This happens when mixing Core Image filters with vImage operations. Both are thread-safe, but ARC will not release vImage buffer data before processing a Core Image object, so you have at some point two copies of an image in memory.
Accordingly, you never consider your knowledge of thread safety to be complete without understanding of threading and concurrency—and that goes double for any answer to questions about thread safety. In short: the proper question is, how does thread-safety apply to memory usage, whenever you're talking about image processing.
If you're just kicking the tires here, you need to wait to pose your question until you've encountered a real problem. But, if you're planning your next move, you need to know how to execute image processing commands sequentially, and with manual deallocation. You must design your app so that there is only one copy of the image being processing in memory. Never rely on automatic deallocation—thread-safe or not—to make that call for you. IT WILL NOT WORK.

Debug thread safety issue on iOS

I've got a thread safety bug somewhere in a fairly large set of code. It's reproducible as a random crash simply by scrolling around in my CATiledLayer for a few seconds in the simulator, and solvable by locking my drawing code into a single thread (which is not ideal, since CATiledLayer is designed to be multi-threaded and my drawing code is slow enough to need it).
How do I go about debugging a thread safety issue? I suspect it's somewhere in my code to lazily fetch (and cache) the data which is being drawn, but that doesn't narrow it down much.
I've skim read the Concurrency Programming Guide, but don't see anything that talks about debugging, it just talks about how to structure your code.
Which concurrency method do you use? GCD or NSThread? And if I can't convince you to use single thread for drawing, try to use #syncronized in your setter/getter methods (or atomic properties, if you use synthesized setters/getters).