questions about OpenGL with multilpe threads

Even know nothing about how OpenGL implementation is organized I can assume that program object state is probably affected, and if its shared I should provide synced access. But what let me think that it must not touch shader object (maybe any counter inside it or something like), or pipeline object this program is binded to, or uniform buffer, this program is linked with? Would it access other state? probably not, but how can I be sure?

You don’t “assume that program object state is probably affected;” the OpenGL specification tells you that it is affected. You’re thinking about this way too hard and at too low of a level.

OpenGL requires that the implementation of AttachShader must associate that particular program object with the given shader object. OpenGL considers this “program object state”.

How the implementation stores this is irrelevant. It could be in the program object; it may have a list of pointers to shader objects. It could be in some “global” array. Maybe the implementation needs back pointers in the shader objects, so that they can refer to any owning program objects.

But none of that matters. What matters is the following, which OpenGL requires:

1: AttachShader will affect that state. It will create an association between the particular program and the particular shader object.

2: After calling AttachShader, GetAttachedShaders will return the particular shader object as one of the list of shaders attached to this program, so long as the shader object still exists and the shader object has not been detached with a call to DetachShader.

3: A call to LinkProgram will cause that compiled shader, and any others currently attached, to be linked within the program object.

Remember: OpenGL is reentrant. The reentrant guarantee only stipulates that, so long as you are calling functions that change the state of different OpenGL objects, you may call any functions on any threads you want. Once you start messing with the same OpenGL objects on two threads, then you have to synchronize access.

AttachShader uses two objects. And since it uses two objects, you must synchronize access to those two objects. Because this function does not modify OpenGL state associated with program pipeline objects, uniform buffers, textures, or anything like that, then the OpenGL state of these objects cannot be affected by calling AttachShader.

I say “OpenGL state” because I’m talking about the state defined by the OpenGL spec. Similarly “OpenGL objects” means objects defined by the OpenGL spec. Only OpenGL state can affect the OpenGL-defined contents of OpenGL objects, and only OpenGL state can affect the OpenGL-defined results of OpenGL rendering. If the implementation of AttachShader needs to communicate with objects not affected as OpenGL defines (for implementation reasons), then the implementation must not allow this to affect the outcome.

So if attaching a shader to a program requires an implementation to peek at the pipeline object(s) the program is attached to, the implementation must do so in such a way that it cannot affect the actual OpenGL state or anything of the kind. This includes reentrancy. This is an implementation detail that OpenGL does not allow to be exposed to the user.

Implementation details must remain hidden behind the abstraction. That is OpenGL’s primary purpose.

how could multiple shader objects of the same type be attached to a single program object? I see no way to select which one of those will be used for rendering and for uniform binding. Have I miss something?

Yes.

GLSL’s compilation model mirrors that of C. In C, you compile source code into one or more object files. These can even be bundled together into libraries.

But to build an executable program in C, you must take one or more object files and link them into a program.

The same goes for GLSL. You compile GLSL source code into shader objects, just like you compile C source code into object files. You link one or more shader objects into a program, just like you link one or more object files into a program.

There is no requirement that a shader object must have all of the code for a particular shader stage. Just as in C; not every object file must define “main”.

The difference is that shaders tend to be sufficiently short that this kind of compile/link model isn’t too useful. You generally don’t see libraries of shader functions that you use where needed. It happens, but it’s not the typical way that you make programs.

However, the functionality is certainly available. It works exactly like C. To access functions defined in one object file from another, the other object file must have function declarations. But only the declaration; not the definition. The linking step attaches those function declarations to their actual implementations, regardless of which object file they happen to come from.