You can create shaders anytime. There's no hard limit to how many shader objects you can have. They obviously use memory, but they're not very large, and having a couple of dozen should not be a problem at all.
The main tradeoff with building a lot of shaders at startup is normally startup time. Shader compilation is a fairly expensive process. For high-end games with thousands of shaders, that's a serious problem. Again, with the numbers you're talking about, I don't think it will be significant.
If you want to continue with deferred shader compilation, you are on the right track with delegating the compilation to the rendering thread. You need to have your OpenGL context current, and when using GLSurfaceView
in Android, it's the rendering thread that operates on the context. Not totally sure why your attempt with queueEvent
did not work. It's possible that while you ended up in the rendering thread, the context was not current. If that's the problem, it could most likely be fixed.
What I would try instead is have the user thread set a member variable in the GLSurfaceView when it wants to change shaders, specifying the new requested shader (watch out for thread safety on the member variable). Then the rendering thread can check in onDrawFrame()
if the requested shader is different from the current shader. If it's different, check if the requested shader is already compiled, by for example keeping a map of shader names to shader objects. If it's not compiled yet, compile it, and store it in the map. Make the new shader current, then render.
There's another approach, but I don't think it's simpler. You can create another EGLContext in your GUI thread, in the same share group as the rendering context. Then you can compile the shaders in the UI thread. You'll still need synchronization with the rendering thread to let it know when a new shader is ready to be used. You also risk running into bugs because object sharing between contexts isn't used much on Android, and I wouldn't be surprised at all if it doesn't work properly on all devices.