What if we want to update a texture while rendering? Ideally we'd like to have the texture updating running 100% asynchronously from the render loop, with no blocking or locks. The short of it is that this is possible by using a second texture (which is swapped in using atomic operations); why you can't just call glTexImage2D from a thread has a more complex answer.
The answer lies in Appendix D of the OpenGL specification, which describes the rules for state update when an object is changed. The basic rules are:
- You always see state change immediately in your own context.
- You don't see a change in another context until you bind the object at least once after the state change is known to have completed.
- The pointer to storage of an object is state. If a command changes that storage (e.g. respecify a texture in another format), the state rules apply!
- You don't see the state until after you bind, but if you're dealing with a stale pointer, the state may not be useful before you bind. I'm not sure how actual GL implementations manage this - I've seen white flashes for textures on OS X when incorrectly dealing with state propagation.
- The spec requires completion in the server, e.g. after a "finish" (or a sync object in the new 3.2 spec, but that's another blog post). That's a pretty harsh condition, and I believe that most gl drivers will accept a flush. Newer, more modern drivers may require a real sync and not a flush - glFlush only works because there is serialization in communication to the card.
That's an ugly enough condition that with X-Plane we simply double-buffer: we allocate a whole new texture object, then use atomic operations to swap it in by ID, then deallocate the old one (on the worker thread). If you think about how texture memory works, there are only two other options:
- Client code holds off rendering while the async happens (the texture itself could be in an inconsistent state).
- The driver double-buffers for you, so that the old bind of the old texture isn't invalid. It's unclear to me from the spec whether this is required of the driver and what the cost would be. It strikes me as inefficient at best.