For textures we use a slightly differntn strategy. The problem is that we (theoretically) need our textures immediately - that is, if we hit a part of the scene graph that references an unloaded texture, we still need to draw something.
Rather than have the state setup go into some fallback "untextured" mode, we use a proxy-and-switch scheme.
- When we first hit the need for a texture, we create one of our C++ objects that manages the texture. This texture object is inited to refer to a dummy gray texture that we use as our proxy for all unloaded textures.
- We queue the texture object to be loaded approximately whenever we get around to it. This might come up soon or it might take a while, depending on how much background work is being done.
- When a worker thread finally gets around to loading the texture, it loads the real image into a new texture "name" (GLuint texture ID).
- When the load is done and flushed, we do an atomic swap , swapping out the old gray proxy texture and swapping in the new texture.
And since the C++ texture object always has something in it, we can use the same shaders even before we've loaded, which simplifies the casing for shader setup quite a bit.