+ GET_CURRENT_CONTEXT(ctx);
+ const char *api_name = "glGetProgramStageiv";
+ struct gl_shader_program *shProg;
+ struct gl_linked_shader *sh;
+ gl_shader_stage stage;
+
+ if (!_mesa_has_shader_subroutine(ctx)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
+ return;
+ }
+
+ if (!_mesa_validate_shader_target(ctx, shadertype)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
+ return;
+ }
+
+ shProg = _mesa_lookup_shader_program_err(ctx, program, api_name);
+ if (!shProg)
+ return;
+
+ stage = _mesa_shader_enum_to_shader_stage(shadertype);
+ sh = shProg->_LinkedShaders[stage];
+ if (!sh) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
+ return;
+ }
+
+ switch (pname) {
+ case GL_ACTIVE_SUBROUTINES:
+ values[0] = sh->NumSubroutineFunctions;
+ break;
+ case GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS:
+ values[0] = sh->NumSubroutineUniformRemapTable;
+ break;
+ case GL_ACTIVE_SUBROUTINE_UNIFORMS:
+ values[0] = sh->NumSubroutineUniforms;
+ break;
+ case GL_ACTIVE_SUBROUTINE_MAX_LENGTH:
+ {
+ unsigned i;
+ GLint max_len = 0;
+ GLenum resource_type;
+ struct gl_program_resource *res;
+
+ resource_type = _mesa_shader_stage_to_subroutine(stage);
+ for (i = 0; i < sh->NumSubroutineFunctions; i++) {
+ res = _mesa_program_resource_find_index(shProg, resource_type, i);
+ if (res) {
+ const GLint len = strlen(_mesa_program_resource_name(res)) + 1;
+ if (len > max_len)
+ max_len = len;
+ }
+ }
+ values[0] = max_len;
+ break;
+ }
+ case GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH:
+ {
+ unsigned i;
+ GLint max_len = 0;
+ GLenum resource_type;
+ struct gl_program_resource *res;
+
+ resource_type = _mesa_shader_stage_to_subroutine_uniform(stage);
+ for (i = 0; i < sh->NumSubroutineUniformRemapTable; i++) {
+ res = _mesa_program_resource_find_index(shProg, resource_type, i);
+ if (res) {
+ const GLint len = strlen(_mesa_program_resource_name(res)) + 1
+ + ((_mesa_program_resource_array_size(res) != 0) ? 3 : 0);
+
+ if (len > max_len)
+ max_len = len;
+ }
+ }
+ values[0] = max_len;
+ break;
+ }
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "%s", api_name);
+ values[0] = -1;
+ break;
+ }
+}
+
+static int
+find_compat_subroutine(struct gl_linked_shader *sh,
+ const struct glsl_type *type)
+{
+ int i, j;
+
+ for (i = 0; i < sh->NumSubroutineFunctions; i++) {
+ struct gl_subroutine_function *fn = &sh->SubroutineFunctions[i];
+ for (j = 0; j < fn->num_compat_types; j++) {
+ if (fn->types[j] == type)
+ return i;
+ }
+ }
+ return 0;
+}
+
+static void
+_mesa_shader_init_subroutine_defaults(struct gl_linked_shader *sh)
+{
+ int i, j;
+
+ for (i = 0; i < sh->NumSubroutineUniformRemapTable; i++) {
+ struct gl_uniform_storage *uni = sh->SubroutineUniformRemapTable[i];
+ int uni_count;
+ int val;
+
+ if (!uni)
+ continue;
+ uni_count = uni->array_elements ? uni->array_elements : 1;
+ val = find_compat_subroutine(sh, uni->type);
+
+ for (j = 0; j < uni_count; j++)
+ memcpy(&uni->storage[j], &val, sizeof(int));
+
+ _mesa_propagate_uniforms_to_driver_storage(uni, 0, uni_count);
+ }
+}
+
+void
+_mesa_shader_program_init_subroutine_defaults(struct gl_shader_program *shProg)
+{
+ int i;
+
+ if (!shProg)
+ return;
+
+ for (i = 0; i < MESA_SHADER_STAGES; i++) {
+ if (!shProg->_LinkedShaders[i])
+ continue;
+
+ _mesa_shader_init_subroutine_defaults(shProg->_LinkedShaders[i]);
+ }