+
+ link(mod);
+ query_uniforms();
+ query_attributes();
+ if(is_compute())
+ {
+ int wg_size[3];
+ glGetProgramiv(id, GL_COMPUTE_WORK_GROUP_SIZE, wg_size);
+ rd.compute_wg_size = LinAl::Vector<unsigned, 3>(wg_size[0], wg_size[1], wg_size[2]);
+ }
+
+ const map<string, unsigned> &block_bindings = compiler.get_uniform_block_bindings();
+ if(!block_bindings.empty())
+ {
+ for(unsigned i=0; i<rd.uniform_blocks.size(); ++i)
+ {
+ auto j = block_bindings.find(rd.uniform_blocks[i].name);
+ if(j!=block_bindings.end())
+ {
+ glUniformBlockBinding(id, i, j->second);
+ rd.uniform_blocks[i].bind_point = j->second;
+ }
+ }
+ }
+
+ const map<string, unsigned> &tex_bindings = compiler.get_texture_bindings();
+ if(!tex_bindings.empty())
+ {
+ if(!ARB_separate_shader_objects)
+ glUseProgram(id);
+ for(const auto &kvp: tex_bindings)
+ {
+ int location = static_cast<const Program *>(this)->get_uniform_location(kvp.first);
+ if(location>=0)
+ {
+ if(ARB_separate_shader_objects)
+ glProgramUniform1i(id, location, kvp.second);
+ else
+ glUniform1i(location, kvp.second);
+ }
+ }
+ }