+ GET_CURRENT_CONTEXT(ctx);
+
+ if (!_mesa_has_tessellation(ctx)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glPatchParameteri");
+ return;
+ }
+
+ if (pname != GL_PATCH_VERTICES) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glPatchParameteri");
+ return;
+ }
+
+ if (value <= 0 || value > ctx->Const.MaxPatchVertices) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glPatchParameteri");
+ return;
+ }
+
+ ctx->TessCtrlProgram.patch_vertices = value;
+}
+
+
+extern void GLAPIENTRY
+_mesa_PatchParameterfv(GLenum pname, const GLfloat *values)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (!_mesa_has_tessellation(ctx)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glPatchParameterfv");
+ return;
+ }
+
+ switch(pname) {
+ case GL_PATCH_DEFAULT_OUTER_LEVEL:
+ FLUSH_VERTICES(ctx, 0);
+ memcpy(ctx->TessCtrlProgram.patch_default_outer_level, values,
+ 4 * sizeof(GLfloat));
+ ctx->NewDriverState |= ctx->DriverFlags.NewDefaultTessLevels;
+ return;
+ case GL_PATCH_DEFAULT_INNER_LEVEL:
+ FLUSH_VERTICES(ctx, 0);
+ memcpy(ctx->TessCtrlProgram.patch_default_inner_level, values,
+ 2 * sizeof(GLfloat));
+ ctx->NewDriverState |= ctx->DriverFlags.NewDefaultTessLevels;
+ return;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glPatchParameterfv");
+ return;
+ }
+}
+
+/**
+ * ARB_shader_subroutine
+ */
+GLint GLAPIENTRY
+_mesa_GetSubroutineUniformLocation(GLuint program, GLenum shadertype,
+ const GLchar *name)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ const char *api_name = "glGetSubroutineUniformLocation";
+ struct gl_shader_program *shProg;
+ GLenum resource_type;
+ gl_shader_stage stage;
+
+ if (!_mesa_has_shader_subroutine(ctx)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
+ return -1;
+ }
+
+ if (!_mesa_validate_shader_target(ctx, shadertype)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
+ return -1;
+ }
+
+ shProg = _mesa_lookup_shader_program_err(ctx, program, api_name);
+ if (!shProg)
+ return -1;
+
+ stage = _mesa_shader_enum_to_shader_stage(shadertype);
+ if (!shProg->_LinkedShaders[stage]) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
+ return -1;
+ }
+
+ resource_type = _mesa_shader_stage_to_subroutine_uniform(stage);
+ return _mesa_program_resource_location(shProg, resource_type, name);
+}
+
+GLuint GLAPIENTRY
+_mesa_GetSubroutineIndex(GLuint program, GLenum shadertype,
+ const GLchar *name)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ const char *api_name = "glGetSubroutineIndex";
+ struct gl_shader_program *shProg;
+ struct gl_program_resource *res;
+ GLenum resource_type;
+ gl_shader_stage stage;
+
+ if (!_mesa_has_shader_subroutine(ctx)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
+ return -1;
+ }
+
+ if (!_mesa_validate_shader_target(ctx, shadertype)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
+ return -1;
+ }
+
+ shProg = _mesa_lookup_shader_program_err(ctx, program, api_name);
+ if (!shProg)
+ return -1;
+
+ stage = _mesa_shader_enum_to_shader_stage(shadertype);
+ if (!shProg->_LinkedShaders[stage]) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
+ return -1;
+ }
+
+ resource_type = _mesa_shader_stage_to_subroutine(stage);
+ res = _mesa_program_resource_find_name(shProg, resource_type, name, NULL);
+ if (!res) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
+ return -1;
+ }
+
+ return _mesa_program_resource_index(shProg, res);
+}
+
+
+GLvoid GLAPIENTRY
+_mesa_GetActiveSubroutineUniformiv(GLuint program, GLenum shadertype,
+ GLuint index, GLenum pname, GLint *values)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ const char *api_name = "glGetActiveSubroutineUniformiv";
+ struct gl_shader_program *shProg;
+ struct gl_shader *sh;
+ gl_shader_stage stage;
+ struct gl_program_resource *res;
+ const struct gl_uniform_storage *uni;
+ GLenum resource_type;
+ int count, i, j;
+
+ 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);
+ resource_type = _mesa_shader_stage_to_subroutine_uniform(stage);
+
+ sh = shProg->_LinkedShaders[stage];
+ if (!sh) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name);
+ return;
+ }
+
+ switch (pname) {
+ case GL_NUM_COMPATIBLE_SUBROUTINES: {
+ res = _mesa_program_resource_find_index(shProg, resource_type, index);
+ if (res) {
+ uni = res->Data;
+ values[0] = uni->num_compatible_subroutines;
+ }