X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Fshaderapi.c;h=f7080847cc1828ef9d66cdccff9662a1a17059e5;hb=a96e946d25d4518d1c73c5d9d0f3d147f42bc416;hp=924423ee6926795e247b72ee7a6322c774729ac6;hpb=789cc87063c0cbb20941053b54fcbe4862912a14;p=mesa.git diff --git a/src/mesa/main/shaderapi.c b/src/mesa/main/shaderapi.c index 924423ee692..f7080847cc1 100644 --- a/src/mesa/main/shaderapi.c +++ b/src/mesa/main/shaderapi.c @@ -38,15 +38,18 @@ #include +#include #include "main/glheader.h" #include "main/context.h" -#include "main/dispatch.h" #include "main/enums.h" +#include "main/glspirv.h" #include "main/hash.h" #include "main/mtypes.h" #include "main/pipelineobj.h" +#include "main/program_binary.h" #include "main/shaderapi.h" #include "main/shaderobj.h" +#include "main/state.h" #include "main/transformfeedback.h" #include "main/uniforms.h" #include "compiler/glsl/glsl_parser_extras.h" @@ -156,6 +159,9 @@ _mesa_free_shader_state(struct gl_context *ctx) { for (int i = 0; i < MESA_SHADER_STAGES; i++) { _mesa_reference_program(ctx, &ctx->Shader.CurrentProgram[i], NULL); + _mesa_reference_shader_program(ctx, + &ctx->Shader.ReferencedPrograms[i], + NULL); } _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, NULL); @@ -423,16 +429,21 @@ delete_shader(struct gl_context *ctx, GLuint shader) } -static void -detach_shader(struct gl_context *ctx, GLuint program, GLuint shader) +static ALWAYS_INLINE void +detach_shader(struct gl_context *ctx, GLuint program, GLuint shader, + bool no_error) { struct gl_shader_program *shProg; GLuint n; GLuint i, j; - shProg = _mesa_lookup_shader_program_err(ctx, program, "glDetachShader"); - if (!shProg) - return; + if (!no_error) { + shProg = _mesa_lookup_shader_program_err(ctx, program, "glDetachShader"); + if (!shProg) + return; + } else { + shProg = _mesa_lookup_shader_program(ctx, program); + } n = shProg->NumShaders; @@ -480,7 +491,7 @@ detach_shader(struct gl_context *ctx, GLuint program, GLuint shader) } /* not found */ - { + if (!no_error) { GLenum err; if (is_shader(ctx, shader) || is_program(ctx, shader)) err = GL_INVALID_OPERATION; @@ -492,12 +503,28 @@ detach_shader(struct gl_context *ctx, GLuint program, GLuint shader) } +static void +detach_shader_error(struct gl_context *ctx, GLuint program, GLuint shader) +{ + detach_shader(ctx, program, shader, false); +} + + +static void +detach_shader_no_error(struct gl_context *ctx, GLuint program, GLuint shader) +{ + detach_shader(ctx, program, shader, true); +} + + /** * Return list of shaders attached to shader program. + * \param objOut returns GLuint ids + * \param handleOut returns GLhandleARB handles */ static void get_attached_shaders(struct gl_context *ctx, GLuint program, GLsizei maxCount, - GLsizei *count, GLuint *obj) + GLsizei *countOut, GLuint *objOut, GLhandleARB *handleOut) { struct gl_shader_program *shProg; @@ -512,14 +539,20 @@ get_attached_shaders(struct gl_context *ctx, GLuint program, GLsizei maxCount, if (shProg) { GLuint i; for (i = 0; i < (GLuint) maxCount && i < shProg->NumShaders; i++) { - obj[i] = shProg->Shaders[i]->Name; + if (objOut) { + objOut[i] = shProg->Shaders[i]->Name; + } + + if (handleOut) { + handleOut[i] = (GLhandleARB) shProg->Shaders[i]->Name; + } + } + if (countOut) { + *countOut = i; } - if (count) - *count = i; } } - /** * glGetHandleARB() - return ID/name of currently bound shader program. */ @@ -637,7 +670,7 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, /* True if geometry shaders (of the form that was adopted into GLSL 1.50 * and GL 3.2) are available in this context */ - const bool has_core_gs = _mesa_has_geometry_shaders(ctx); + const bool has_gs = _mesa_has_geometry_shaders(ctx); const bool has_tess = _mesa_has_tessellation(ctx); /* Are uniform buffer objects available in this context? @@ -738,7 +771,7 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, *params = shProg->TransformFeedback.BufferMode; return; case GL_GEOMETRY_VERTICES_OUT: - if (!has_core_gs) + if (!has_gs) break; if (check_gs_query(ctx, shProg)) { *params = shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]-> @@ -746,7 +779,7 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, } return; case GL_GEOMETRY_SHADER_INVOCATIONS: - if (!has_core_gs || !ctx->Extensions.ARB_gpu_shader5) + if (!has_gs || !ctx->Extensions.ARB_gpu_shader5) break; if (check_gs_query(ctx, shProg)) { *params = shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]-> @@ -754,7 +787,7 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, } return; case GL_GEOMETRY_INPUT_TYPE: - if (!has_core_gs) + if (!has_gs) break; if (check_gs_query(ctx, shProg)) { *params = shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]-> @@ -762,7 +795,7 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, } return; case GL_GEOMETRY_OUTPUT_TYPE: - if (!has_core_gs) + if (!has_gs) break; if (check_gs_query(ctx, shProg)) { *params = shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]-> @@ -807,7 +840,11 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, *params = shProg->BinaryRetreivableHint; return; case GL_PROGRAM_BINARY_LENGTH: - *params = 0; + if (ctx->Const.NumProgramBinaryFormats == 0 || !shProg->data->LinkStatus) { + *params = 0; + } else { + _mesa_get_program_binary_length(ctx, shProg, params); + } return; case GL_ACTIVE_ATOMIC_COUNTER_BUFFERS: if (!ctx->Extensions.ARB_shader_atomic_counters) @@ -836,7 +873,7 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, } case GL_PROGRAM_SEPARABLE: /* If the program has not been linked, return initial value 0. */ - *params = (shProg->data->LinkStatus == linking_failure) ? 0 : shProg->SeparateShader; + *params = (shProg->data->LinkStatus == LINKING_FAILURE) ? 0 : shProg->SeparateShader; return; /* ARB_tessellation_shader */ @@ -933,6 +970,9 @@ get_shaderiv(struct gl_context *ctx, GLuint name, GLenum pname, GLint *params) case GL_SHADER_SOURCE_LENGTH: *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0; break; + case GL_SPIR_V_BINARY_ARB: + *params = (shader->spirv_data != NULL); + break; default: _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)"); return; @@ -1020,11 +1060,21 @@ get_shader_source(struct gl_context *ctx, GLuint shader, GLsizei maxLength, * glShaderSource[ARB]. */ static void -shader_source(struct gl_shader *sh, const GLchar *source) +set_shader_source(struct gl_shader *sh, const GLchar *source) { assert(sh); - if (sh->CompileStatus == compile_skipped && !sh->FallbackSource) { + /* The GL_ARB_gl_spirv spec adds the following to the end of the description + * of ShaderSource: + * + * "If was previously associated with a SPIR-V module (via the + * ShaderBinary command), that association is broken. Upon successful + * completion of this command the SPIR_V_BINARY_ARB state of + * is set to FALSE." + */ + _mesa_shader_spirv_data_reference(&sh->spirv_data, NULL); + + if (sh->CompileStatus == COMPILE_SKIPPED && !sh->FallbackSource) { /* If shader was previously compiled back-up the source in case of cache * fallback. */ @@ -1051,11 +1101,23 @@ _mesa_compile_shader(struct gl_context *ctx, struct gl_shader *sh) if (!sh) return; + /* The GL_ARB_gl_spirv spec says: + * + * "Add a new error for the CompileShader command: + * + * An INVALID_OPERATION error is generated if the SPIR_V_BINARY_ARB + * state of is TRUE." + */ + if (sh->spirv_data) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glCompileShader(SPIR-V)"); + return; + } + if (!sh->Source) { /* If the user called glCompileShader without first calling * glShaderSource, we should fail to compile, but not raise a GL_ERROR. */ - sh->CompileStatus = compile_failure; + sh->CompileStatus = COMPILE_FAILURE; } else { if (ctx->_Shader->Flags & GLSL_DUMP) { _mesa_log("GLSL source for %s shader %d:\n", @@ -1111,21 +1173,24 @@ _mesa_compile_shader(struct gl_context *ctx, struct gl_shader *sh) /** * Link a program's shaders. */ -void -_mesa_link_program(struct gl_context *ctx, struct gl_shader_program *shProg) +static ALWAYS_INLINE void +link_program(struct gl_context *ctx, struct gl_shader_program *shProg, + bool no_error) { if (!shProg) return; - /* From the ARB_transform_feedback2 specification: - * "The error INVALID_OPERATION is generated by LinkProgram if is - * the name of a program being used by one or more transform feedback - * objects, even if the objects are not currently bound or are paused." - */ - if (_mesa_transform_feedback_is_using_program(ctx, shProg)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glLinkProgram(transform feedback is using the program)"); - return; + if (!no_error) { + /* From the ARB_transform_feedback2 specification: + * "The error INVALID_OPERATION is generated by LinkProgram if + * is the name of a program being used by one or more transform feedback + * objects, even if the objects are not currently bound or are paused." + */ + if (_mesa_transform_feedback_is_using_program(ctx, shProg)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glLinkProgram(transform feedback is using the program)"); + return; + } } unsigned programs_in_use = 0; @@ -1190,12 +1255,14 @@ _mesa_link_program(struct gl_context *ctx, struct gl_shader_program *shProg) ralloc_free(filename); } - if (shProg->data->LinkStatus == linking_failure && + if (shProg->data->LinkStatus == LINKING_FAILURE && (ctx->_Shader->Flags & GLSL_REPORT_ERRORS)) { _mesa_debug(ctx, "Error linking program %u:\n%s\n", shProg->Name, shProg->data->InfoLog); } + _mesa_update_vertex_processing_mode(ctx); + /* debug code */ if (0) { GLuint i; @@ -1213,6 +1280,27 @@ _mesa_link_program(struct gl_context *ctx, struct gl_shader_program *shProg) } +static void +link_program_error(struct gl_context *ctx, struct gl_shader_program *shProg) +{ + link_program(ctx, shProg, false); +} + + +static void +link_program_no_error(struct gl_context *ctx, struct gl_shader_program *shProg) +{ + link_program(ctx, shProg, true); +} + + +void +_mesa_link_program(struct gl_context *ctx, struct gl_shader_program *shProg) +{ + link_program_error(ctx, shProg); +} + + /** * Print basic shader info (for debug). */ @@ -1495,11 +1583,27 @@ _mesa_DeleteShader(GLuint name) } +void GLAPIENTRY +_mesa_DetachObjectARB_no_error(GLhandleARB program, GLhandleARB shader) +{ + GET_CURRENT_CONTEXT(ctx); + detach_shader_no_error(ctx, program, shader); +} + + void GLAPIENTRY _mesa_DetachObjectARB(GLhandleARB program, GLhandleARB shader) { GET_CURRENT_CONTEXT(ctx); - detach_shader(ctx, program, shader); + detach_shader_error(ctx, program, shader); +} + + +void GLAPIENTRY +_mesa_DetachShader_no_error(GLuint program, GLuint shader) +{ + GET_CURRENT_CONTEXT(ctx); + detach_shader_no_error(ctx, program, shader); } @@ -1507,7 +1611,7 @@ void GLAPIENTRY _mesa_DetachShader(GLuint program, GLuint shader) { GET_CURRENT_CONTEXT(ctx); - detach_shader(ctx, program, shader); + detach_shader_error(ctx, program, shader); } @@ -1516,7 +1620,7 @@ _mesa_GetAttachedObjectsARB(GLhandleARB container, GLsizei maxCount, GLsizei * count, GLhandleARB * obj) { GET_CURRENT_CONTEXT(ctx); - get_attached_shaders(ctx, container, maxCount, count, obj); + get_attached_shaders(ctx, (GLuint)container, maxCount, count, NULL, obj); } @@ -1525,7 +1629,7 @@ _mesa_GetAttachedShaders(GLuint program, GLsizei maxCount, GLsizei *count, GLuint *obj) { GET_CURRENT_CONTEXT(ctx); - get_attached_shaders(ctx, program, maxCount, count, obj); + get_attached_shaders(ctx, program, maxCount, count, obj, NULL); } @@ -1650,14 +1754,28 @@ _mesa_IsShader(GLuint name) } +void GLAPIENTRY +_mesa_LinkProgram_no_error(GLuint programObj) +{ + GET_CURRENT_CONTEXT(ctx); + + struct gl_shader_program *shProg = + _mesa_lookup_shader_program(ctx, programObj); + link_program_no_error(ctx, shProg); +} + + void GLAPIENTRY _mesa_LinkProgram(GLuint programObj) { GET_CURRENT_CONTEXT(ctx); + if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glLinkProgram %u\n", programObj); - _mesa_link_program(ctx, _mesa_lookup_shader_program_err(ctx, programObj, - "glLinkProgram")); + + struct gl_shader_program *shProg = + _mesa_lookup_shader_program_err(ctx, programObj, "glLinkProgram"); + link_program_error(ctx, shProg); } #ifdef ENABLE_SHADER_CACHE @@ -1779,23 +1897,26 @@ read_shader(const gl_shader_stage stage, const char *source) * Basically, concatenate the source code strings into one long string * and pass it to _mesa_shader_source(). */ -void GLAPIENTRY -_mesa_ShaderSource(GLuint shaderObj, GLsizei count, - const GLchar * const * string, const GLint * length) +static ALWAYS_INLINE void +shader_source(struct gl_context *ctx, GLuint shaderObj, GLsizei count, + const GLchar *const *string, const GLint *length, bool no_error) { - GET_CURRENT_CONTEXT(ctx); GLint *offsets; GLsizei i, totalLength; GLcharARB *source; struct gl_shader *sh; - sh = _mesa_lookup_shader_err(ctx, shaderObj, "glShaderSourceARB"); - if (!sh) - return; + if (!no_error) { + sh = _mesa_lookup_shader_err(ctx, shaderObj, "glShaderSourceARB"); + if (!sh) + return; - if (string == NULL) { - _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSourceARB"); - return; + if (string == NULL) { + _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSourceARB"); + return; + } + } else { + sh = _mesa_lookup_shader(ctx, shaderObj); } /* @@ -1809,7 +1930,7 @@ _mesa_ShaderSource(GLuint shaderObj, GLsizei count, } for (i = 0; i < count; i++) { - if (string[i] == NULL) { + if (!no_error && string[i] == NULL) { free((GLvoid *) offsets); _mesa_error(ctx, GL_INVALID_OPERATION, "glShaderSourceARB(null string)"); @@ -1859,12 +1980,30 @@ _mesa_ShaderSource(GLuint shaderObj, GLsizei count, } #endif /* ENABLE_SHADER_CACHE */ - shader_source(sh, source); + set_shader_source(sh, source); free(offsets); } +void GLAPIENTRY +_mesa_ShaderSource_no_error(GLuint shaderObj, GLsizei count, + const GLchar *const *string, const GLint *length) +{ + GET_CURRENT_CONTEXT(ctx); + shader_source(ctx, shaderObj, count, string, length, true); +} + + +void GLAPIENTRY +_mesa_ShaderSource(GLuint shaderObj, GLsizei count, + const GLchar *const *string, const GLint *length) +{ + GET_CURRENT_CONTEXT(ctx); + shader_source(ctx, shaderObj, count, string, length, false); +} + + static ALWAYS_INLINE void use_program(GLuint program, bool no_error) { @@ -1932,6 +2071,8 @@ use_program(GLuint program, bool no_error) _mesa_BindProgramPipeline(ctx->Pipeline.Current->Name); } } + + _mesa_update_vertex_processing_mode(ctx); } @@ -2030,9 +2171,7 @@ _mesa_ShaderBinary(GLint n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLint length) { GET_CURRENT_CONTEXT(ctx); - (void) shaders; - (void) binaryformat; - (void) binary; + struct gl_shader **sh; /* Page 68, section 7.2 'Shader Binaries" of the of the OpenGL ES 3.1, and * page 88 of the OpenGL 4.5 specs state: @@ -2046,6 +2185,37 @@ _mesa_ShaderBinary(GLint n, const GLuint* shaders, GLenum binaryformat, return; } + /* Get all shader objects at once so we can make the operation + * all-or-nothing. + */ + if (n > SIZE_MAX / sizeof(*sh)) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glShaderBinary(count)"); + return; + } + + sh = alloca(sizeof(*sh) * (size_t)n); + if (!sh) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glShaderBinary"); + return; + } + + for (int i = 0; i < n; ++i) { + sh[i] = _mesa_lookup_shader_err(ctx, shaders[i], "glShaderBinary"); + if (!sh[i]) + return; + } + + if (binaryformat == GL_SHADER_BINARY_FORMAT_SPIR_V_ARB) { + if (!ctx->Extensions.ARB_gl_spirv) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glShaderBinary(SPIR-V)"); + } else if (n > 0) { + _mesa_spirv_shader_binary(ctx, (unsigned) n, sh, binary, + (size_t) length); + } + + return; + } + _mesa_error(ctx, GL_INVALID_ENUM, "glShaderBinary(format)"); } @@ -2092,12 +2262,15 @@ _mesa_GetProgramBinary(GLuint program, GLsizei bufSize, GLsizei *length, return; } - *length = 0; - _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetProgramBinary(driver supports zero binary formats)"); - - (void) binaryFormat; - (void) binary; + if (ctx->Const.NumProgramBinaryFormats == 0) { + *length = 0; + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetProgramBinary(driver supports zero binary formats)"); + } else { + _mesa_get_program_binary(ctx, shProg, bufSize, length, binaryFormat, + binary); + assert(*length == 0 || *binaryFormat == GL_PROGRAM_BINARY_FORMAT_MESA); + } } void GLAPIENTRY @@ -2111,8 +2284,8 @@ _mesa_ProgramBinary(GLuint program, GLenum binaryFormat, if (!shProg) return; - (void) binaryFormat; - (void) binary; + _mesa_clear_shader_program_data(ctx, shProg); + shProg->data = _mesa_create_shader_program_data(); /* Section 2.3.1 (Errors) of the OpenGL 4.5 spec says: * @@ -2124,34 +2297,32 @@ _mesa_ProgramBinary(GLuint program, GLenum binaryFormat, return; } - /* The ARB_get_program_binary spec says: - * - * " and must be those returned by a previous - * call to GetProgramBinary, and must be the length of the - * program binary as returned by GetProgramBinary or GetProgramiv with - * PROGRAM_BINARY_LENGTH. Loading the program binary will fail, - * setting the LINK_STATUS of to FALSE, if these conditions - * are not met." - * - * Since any value of binaryFormat passed "is not one of those specified as - * allowable for [this] command, an INVALID_ENUM error is generated." - */ - shProg->data->LinkStatus = linking_failure; - _mesa_error(ctx, GL_INVALID_ENUM, "glProgramBinary"); + if (ctx->Const.NumProgramBinaryFormats == 0 || + binaryFormat != GL_PROGRAM_BINARY_FORMAT_MESA) { + /* The ARB_get_program_binary spec says: + * + * " and must be those returned by a previous + * call to GetProgramBinary, and must be the length of the + * program binary as returned by GetProgramBinary or GetProgramiv with + * PROGRAM_BINARY_LENGTH. Loading the program binary will fail, + * setting the LINK_STATUS of to FALSE, if these conditions + * are not met." + * + * Since any value of binaryFormat passed "is not one of those specified as + * allowable for [this] command, an INVALID_ENUM error is generated." + */ + shProg->data->LinkStatus = LINKING_FAILURE; + _mesa_error(ctx, GL_INVALID_ENUM, "glProgramBinary"); + } else { + _mesa_program_binary(ctx, shProg, binaryFormat, binary, length); + } } -void GLAPIENTRY -_mesa_ProgramParameteri(GLuint program, GLenum pname, GLint value) +static ALWAYS_INLINE void +program_parameteri(struct gl_context *ctx, struct gl_shader_program *shProg, + GLuint pname, GLint value, bool no_error) { - struct gl_shader_program *shProg; - GET_CURRENT_CONTEXT(ctx); - - shProg = _mesa_lookup_shader_program_err(ctx, program, - "glProgramParameteri"); - if (!shProg) - return; - switch (pname) { case GL_PROGRAM_BINARY_RETRIEVABLE_HINT: /* This enum isn't part of the OES extension for OpenGL ES 2.0, but it @@ -2167,7 +2338,7 @@ _mesa_ProgramParameteri(GLuint program, GLenum pname, GLint value) * "An INVALID_VALUE error is generated if the argument to * ProgramParameteri is not TRUE or FALSE." */ - if (value != GL_TRUE && value != GL_FALSE) { + if (!no_error && value != GL_TRUE && value != GL_FALSE) { goto invalid_value; } @@ -2198,15 +2369,17 @@ _mesa_ProgramParameteri(GLuint program, GLenum pname, GLint value) /* Spec imply that the behavior is the same as ARB_get_program_binary * Chapter 7.3 Program Objects */ - if (value != GL_TRUE && value != GL_FALSE) { + if (!no_error && value != GL_TRUE && value != GL_FALSE) { goto invalid_value; } shProg->SeparateShader = value; return; default: - _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameteri(pname=%s)", - _mesa_enum_to_string(pname)); + if (!no_error) { + _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameteri(pname=%s)", + _mesa_enum_to_string(pname)); + } return; } @@ -2219,6 +2392,31 @@ invalid_value: } +void GLAPIENTRY +_mesa_ProgramParameteri_no_error(GLuint program, GLenum pname, GLint value) +{ + GET_CURRENT_CONTEXT(ctx); + + struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, program); + program_parameteri(ctx, shProg, pname, value, true); +} + + +void GLAPIENTRY +_mesa_ProgramParameteri(GLuint program, GLenum pname, GLint value) +{ + struct gl_shader_program *shProg; + GET_CURRENT_CONTEXT(ctx); + + shProg = _mesa_lookup_shader_program_err(ctx, program, + "glProgramParameteri"); + if (!shProg) + return; + + program_parameteri(ctx, shProg, pname, value, false); +} + + void _mesa_use_program(struct gl_context *ctx, gl_shader_stage stage, struct gl_shader_program *shProg, struct gl_program *prog, @@ -2241,6 +2439,8 @@ _mesa_use_program(struct gl_context *ctx, gl_shader_stage stage, &shTarget->ReferencedPrograms[stage], shProg); _mesa_reference_program(ctx, target, prog); + if (stage == MESA_SHADER_VERTEX) + _mesa_update_vertex_processing_mode(ctx); return; } @@ -2324,13 +2524,13 @@ _mesa_CreateShaderProgramv(GLenum type, GLsizei count, if (compiled) { attach_shader_err(ctx, program, shader, "glCreateShaderProgramv"); _mesa_link_program(ctx, shProg); - detach_shader(ctx, program, shader); + detach_shader_error(ctx, program, shader); #if 0 /* Possibly... */ if (active-user-defined-varyings-in-linked-program) { append-error-to-info-log; - shProg->data->LinkStatus = linking_failure; + shProg->data->LinkStatus = LINKING_FAILURE; } #endif }