X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Fshaderapi.c;h=19d7a3ab44003261b2bc601481fec61f093cbded;hb=1fc346d2bec83adff7e4ff05b28e8855c54eb603;hp=7430cfeeb8de2f0b7337575a2b6cf03fc7c15ecd;hpb=6d7660cf4b7c0c73b4394f09dd149c6b0386115c;p=mesa.git diff --git a/src/mesa/main/shaderapi.c b/src/mesa/main/shaderapi.c index 7430cfeeb8d..19d7a3ab440 100644 --- a/src/mesa/main/shaderapi.c +++ b/src/mesa/main/shaderapi.c @@ -29,26 +29,27 @@ * * Implementation of GLSL-related API functions. * The glUniform* functions are in uniforms.c - * - * - * XXX things to do: - * 1. Check that the right error code is generated for all _mesa_error() calls. - * 2. Insert FLUSH_VERTICES calls in various places */ +#include #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/builtin_functions.h" #include "compiler/glsl/glsl_parser_extras.h" #include "compiler/glsl/ir.h" #include "compiler/glsl/ir_uniform.h" @@ -60,6 +61,9 @@ #include "util/hash_table.h" #include "util/mesa-sha1.h" #include "util/crc32.h" +#include "util/os_file.h" +#include "util/simple_list.h" +#include "util/u_string.h" /** * Return mask of GLSL_x flags by examining the MESA_GLSL env var. @@ -77,6 +81,8 @@ _mesa_get_shader_flags(void) flags |= GLSL_DUMP; if (strstr(env, "log")) flags |= GLSL_LOG; + if (strstr(env, "cache_fb")) + flags |= GLSL_CACHE_FALLBACK; if (strstr(env, "cache_info")) flags |= GLSL_CACHE_INFO; if (strstr(env, "nopvert")) @@ -154,6 +160,11 @@ _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); + free(ctx->SubroutineIndex[i].IndexPtr); + ctx->SubroutineIndex[i].IndexPtr = NULL; } _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, NULL); @@ -242,7 +253,27 @@ is_shader(struct gl_context *ctx, GLuint name) * Attach shader to a shader program. */ static void -attach_shader(struct gl_context *ctx, GLuint program, GLuint shader) +attach_shader(struct gl_context *ctx, struct gl_shader_program *shProg, + struct gl_shader *sh) +{ + GLuint n = shProg->NumShaders; + + shProg->Shaders = realloc(shProg->Shaders, + (n + 1) * sizeof(struct gl_shader *)); + if (!shProg->Shaders) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader"); + return; + } + + /* append */ + shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */ + _mesa_reference_shader(ctx, &shProg->Shaders[n], sh); + shProg->NumShaders++; +} + +static void +attach_shader_err(struct gl_context *ctx, GLuint program, GLuint shader, + const char *caller) { struct gl_shader_program *shProg; struct gl_shader *sh; @@ -250,11 +281,11 @@ attach_shader(struct gl_context *ctx, GLuint program, GLuint shader) const bool same_type_disallowed = _mesa_is_gles(ctx); - shProg = _mesa_lookup_shader_program_err(ctx, program, "glAttachShader"); + shProg = _mesa_lookup_shader_program_err(ctx, program, caller); if (!shProg) return; - sh = _mesa_lookup_shader_err(ctx, shader, "glAttachShader"); + sh = _mesa_lookup_shader_err(ctx, shader, caller); if (!sh) { return; } @@ -268,7 +299,7 @@ attach_shader(struct gl_context *ctx, GLuint program, GLuint shader) * "The error INVALID_OPERATION is generated by AttachObjectARB * if is already attached to ." */ - _mesa_error(ctx, GL_INVALID_OPERATION, "glAttachShader"); + _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller); return; } else if (same_type_disallowed && shProg->Shaders[i]->Stage == sh->Stage) { @@ -280,25 +311,25 @@ attach_shader(struct gl_context *ctx, GLuint program, GLuint shader) * is generated if [...] another shader object of the same type * as shader is already attached to program." */ - _mesa_error(ctx, GL_INVALID_OPERATION, "glAttachShader"); + _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller); return; } } - /* grow list */ - shProg->Shaders = realloc(shProg->Shaders, - (n + 1) * sizeof(struct gl_shader *)); - if (!shProg->Shaders) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader"); - return; - } - - /* append */ - shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */ - _mesa_reference_shader(ctx, &shProg->Shaders[n], sh); - shProg->NumShaders++; + attach_shader(ctx, shProg, sh); } +static void +attach_shader_no_error(struct gl_context *ctx, GLuint program, GLuint shader) +{ + struct gl_shader_program *shProg; + struct gl_shader *sh; + + shProg = _mesa_lookup_shader_program(ctx, program); + sh = _mesa_lookup_shader(ctx, shader); + + attach_shader(ctx, shProg, sh); +} static GLuint create_shader(struct gl_context *ctx, GLenum type) @@ -306,12 +337,6 @@ create_shader(struct gl_context *ctx, GLenum type) struct gl_shader *sh; GLuint name; - if (!_mesa_validate_shader_target(ctx, type)) { - _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(%s)", - _mesa_enum_to_string(type)); - return 0; - } - _mesa_HashLockMutex(ctx->Shared->ShaderObjects); name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1); sh = _mesa_new_shader(name, _mesa_shader_enum_to_shader_stage(type)); @@ -323,6 +348,19 @@ create_shader(struct gl_context *ctx, GLenum type) } +static GLuint +create_shader_err(struct gl_context *ctx, GLenum type, const char *caller) +{ + if (!_mesa_validate_shader_target(ctx, type)) { + _mesa_error(ctx, GL_INVALID_ENUM, "%s(%s)", + caller, _mesa_enum_to_string(type)); + return 0; + } + + return create_shader(ctx, type); +} + + static GLuint create_shader_program(struct gl_context *ctx) { @@ -394,16 +432,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; @@ -434,7 +477,7 @@ detach_shader(struct gl_context *ctx, GLuint program, GLuint shader) shProg->Shaders = newList; shProg->NumShaders = n - 1; -#ifdef DEBUG +#ifndef NDEBUG /* sanity check - make sure the new list's entries are sensible */ for (j = 0; j < shProg->NumShaders; j++) { assert(shProg->Shaders[j]->Stage == MESA_SHADER_VERTEX || @@ -451,7 +494,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; @@ -463,12 +506,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; @@ -483,14 +542,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. */ @@ -585,6 +650,13 @@ check_tes_query(struct gl_context *ctx, const struct gl_shader_program *shProg) return false; } +/** + * Return the length of a string, or 0 if the pointer passed in is NULL + */ +static size_t strlen_or_zero(const char *s) +{ + return s ? strlen(s) : 0; +} /** * glGetProgramiv() - get shader program state. @@ -608,7 +680,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? @@ -627,6 +699,12 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, case GL_DELETE_STATUS: *params = shProg->DeletePending; return; + case GL_COMPLETION_STATUS_ARB: + if (ctx->Driver.GetShaderProgramCompletionStatus) + *params = ctx->Driver.GetShaderProgramCompletionStatus(ctx, shProg); + else + *params = GL_TRUE; + return; case GL_LINK_STATUS: *params = shProg->data->LinkStatus ? GL_TRUE : GL_FALSE; return; @@ -666,11 +744,23 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, if (shProg->data->UniformStorage[i].is_shader_storage) continue; + /* From ARB_gl_spirv spec: + * + * "If pname is ACTIVE_UNIFORM_MAX_LENGTH, the length of the + * longest active uniform name, including a null terminator, is + * returned. If no active uniforms exist, zero is returned. If no + * name reflection information is available, one is returned." + * + * We are setting 0 here, as below it will add 1 for the NUL character. + */ + const GLint base_len = + strlen_or_zero(shProg->data->UniformStorage[i].name); + /* Add one for the terminating NUL character for a non-array, and * 4 for the "[0]" and the NUL for an array. */ - const GLint len = strlen(shProg->data->UniformStorage[i].name) + 1 + - ((shProg->data->UniformStorage[i].array_elements != 0) ? 3 : 0); + const GLint len = base_len + 1 + + ((shProg->data->UniformStorage[i].array_elements != 0) ? 3 : 0); if (len > max_len) max_len = len; @@ -682,19 +772,48 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, case GL_TRANSFORM_FEEDBACK_VARYINGS: if (!has_xfb) break; - *params = shProg->TransformFeedback.NumVarying; + + /* Check first if there are transform feedback varyings specified in the + * shader (ARB_enhanced_layouts). If there isn't any, return the number of + * varyings specified using the API. + */ + if (shProg->last_vert_prog && + shProg->last_vert_prog->sh.LinkedTransformFeedback->NumVarying > 0) + *params = + shProg->last_vert_prog->sh.LinkedTransformFeedback->NumVarying; + else + *params = shProg->TransformFeedback.NumVarying; return; case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH: { unsigned i; GLint max_len = 0; + bool in_shader_varyings; + int num_varying; + if (!has_xfb) break; - for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) { - /* Add one for the terminating NUL character. + /* Check first if there are transform feedback varyings specified in the + * shader (ARB_enhanced_layouts). If there isn't any, use the ones + * specified using the API. + */ + in_shader_varyings = shProg->last_vert_prog && + shProg->last_vert_prog->sh.LinkedTransformFeedback->NumVarying > 0; + + num_varying = in_shader_varyings ? + shProg->last_vert_prog->sh.LinkedTransformFeedback->NumVarying : + shProg->TransformFeedback.NumVarying; + + for (i = 0; i < num_varying; i++) { + const char *name = in_shader_varyings ? + shProg->last_vert_prog->sh.LinkedTransformFeedback->Varyings[i].Name + : shProg->TransformFeedback.VaryingNames[i]; + + /* Add one for the terminating NUL character. We have to use + * strlen_or_zero, as for shaders constructed from SPIR-V binaries, + * it is possible that no name reflection information is available. */ - const GLint len = - strlen(shProg->TransformFeedback.VaryingNames[i]) + 1; + const GLint len = strlen_or_zero(name) + 1; if (len > max_len) max_len = len; @@ -709,7 +828,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]-> @@ -717,15 +836,17 @@ 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 || + (_mesa_is_desktop_gl(ctx) && !ctx->Extensions.ARB_gpu_shader5)) { break; + } if (check_gs_query(ctx, shProg)) { *params = shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]-> Program->info.gs.invocations; } 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]-> @@ -733,7 +854,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]-> @@ -748,9 +869,16 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, break; for (i = 0; i < shProg->data->NumUniformBlocks; i++) { - /* Add one for the terminating NUL character. + /* Add one for the terminating NUL character. Name can be NULL, in + * that case, from ARB_gl_spirv: + * "If pname is ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, the length of + * the longest active uniform block name, including the null + * terminator, is returned. If no active uniform blocks exist, + * zero is returned. If no name reflection information is + * available, one is returned." */ - const GLint len = strlen(shProg->data->UniformBlocks[i].Name) + 1; + const GLint len = + strlen_or_zero(shProg->data->UniformBlocks[i].Name) + 1; if (len > max_len) max_len = len; @@ -775,10 +903,14 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, if (!_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx)) break; - *params = shProg->BinaryRetreivableHint; + *params = shProg->BinaryRetrievableHint; 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) @@ -807,7 +939,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 */ @@ -894,6 +1026,10 @@ get_shaderiv(struct gl_context *ctx, GLuint name, GLenum pname, GLint *params) case GL_DELETE_STATUS: *params = shader->DeletePending; break; + case GL_COMPLETION_STATUS_ARB: + /* _mesa_glsl_compile_shader is not offloaded to other threads. */ + *params = GL_TRUE; + return; case GL_COMPILE_STATUS: *params = shader->CompileStatus ? GL_TRUE : GL_FALSE; break; @@ -904,6 +1040,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; @@ -991,11 +1130,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. */ @@ -1012,6 +1161,14 @@ shader_source(struct gl_shader *sh, const GLchar *source) #endif } +static void +ensure_builtin_types(struct gl_context *ctx) +{ + if (!ctx->shader_builtin_ref) { + _mesa_glsl_builtin_functions_init_or_ref(); + ctx->shader_builtin_ref = true; + } +} /** * Compile a shader. @@ -1022,11 +1179,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", @@ -1034,6 +1203,8 @@ _mesa_compile_shader(struct gl_context *ctx, struct gl_shader *sh) _mesa_log("%s\n", sh->Source); } + ensure_builtin_types(ctx); + /* this call will set the shader->CompileStatus field to indicate if * compilation was successful. */ @@ -1079,24 +1250,50 @@ _mesa_compile_shader(struct gl_context *ctx, struct gl_shader *sh) } +struct update_programs_in_pipeline_params +{ + struct gl_context *ctx; + struct gl_shader_program *shProg; +}; + +static void +update_programs_in_pipeline(GLuint key, void *data, void *userData) +{ + struct update_programs_in_pipeline_params *params = + (struct update_programs_in_pipeline_params *) userData; + struct gl_pipeline_object *obj = (struct gl_pipeline_object *) data; + + for (unsigned stage = 0; stage < MESA_SHADER_STAGES; stage++) { + if (obj->CurrentProgram[stage] && + obj->CurrentProgram[stage]->Id == params->shProg->Name) { + struct gl_program *prog = params->shProg->_LinkedShaders[stage]->Program; + _mesa_use_program(params->ctx, stage, params->shProg, prog, obj); + } + } +} + + /** * 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; @@ -1106,7 +1303,9 @@ _mesa_link_program(struct gl_context *ctx, struct gl_shader_program *shProg) ctx->_Shader->CurrentProgram[stage]->Id == shProg->Name) { programs_in_use |= 1 << stage; } - } + } + + ensure_builtin_types(ctx); FLUSH_VERTICES(ctx, 0); _mesa_glsl_link_shader(ctx, shProg); @@ -1121,7 +1320,7 @@ _mesa_link_program(struct gl_context *ctx, struct gl_shader_program *shProg) * the state of any program pipeline for all stages where the program * is attached." */ - if (shProg->data->LinkStatus && programs_in_use) { + if (shProg->data->LinkStatus) { while (programs_in_use) { const int stage = u_bit_scan(&programs_in_use); @@ -1131,15 +1330,41 @@ _mesa_link_program(struct gl_context *ctx, struct gl_shader_program *shProg) _mesa_use_program(ctx, stage, shProg, prog, ctx->_Shader); } + + if (ctx->Pipeline.Objects) { + struct update_programs_in_pipeline_params params = { + .ctx = ctx, + .shProg = shProg + }; + _mesa_HashWalk(ctx->Pipeline.Objects, update_programs_in_pipeline, + ¶ms); + } } /* Capture .shader_test files. */ const char *capture_path = _mesa_get_shader_capture_path(); if (shProg->Name != 0 && shProg->Name != ~0 && capture_path != NULL) { - FILE *file; - char *filename = ralloc_asprintf(NULL, "%s/%u.shader_test", + /* Find an unused filename. */ + FILE *file = NULL; + char *filename = NULL; + for (unsigned i = 0;; i++) { + if (i) { + filename = ralloc_asprintf(NULL, "%s/%u-%u.shader_test", + capture_path, shProg->Name, i); + } else { + filename = ralloc_asprintf(NULL, "%s/%u.shader_test", capture_path, shProg->Name); - file = fopen(filename, "w"); + } + file = os_file_create_unique(filename, 0644); + if (file) + break; + /* If we are failing for another reason than "this filename already + * exists", we are likely to fail again with another filename, so + * let's just give up */ + if (errno != EEXIST) + break; + ralloc_free(filename); + } if (file) { fprintf(file, "[require]\nGLSL%s >= %u.%02u\n", shProg->IsES ? " ES" : "", @@ -1161,12 +1386,16 @@ _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); + + shProg->BinaryRetrievableHint = shProg->BinaryRetrievableHintPending; + /* debug code */ if (0) { GLuint i; @@ -1184,6 +1413,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). */ @@ -1242,33 +1492,6 @@ _mesa_active_program(struct gl_context *ctx, struct gl_shader_program *shProg, } -static void -use_program(struct gl_context *ctx, gl_shader_stage stage, - struct gl_shader_program *shProg, struct gl_program *new_prog, - struct gl_pipeline_object *shTarget) -{ - struct gl_program **target; - - target = &shTarget->CurrentProgram[stage]; - if (new_prog) { - _mesa_program_init_subroutine_defaults(ctx, new_prog); - } - - if (*target != new_prog) { - /* Program is current, flush it */ - if (shTarget == ctx->_Shader) { - FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS); - } - - _mesa_reference_shader_program(ctx, - &shTarget->ReferencedPrograms[stage], - shProg); - _mesa_reference_program(ctx, target, new_prog); - return; - } -} - - /** * Use the named shader program for subsequent rendering. */ @@ -1280,7 +1503,7 @@ _mesa_use_shader_program(struct gl_context *ctx, struct gl_program *new_prog = NULL; if (shProg && shProg->_LinkedShaders[i]) new_prog = shProg->_LinkedShaders[i]->Program; - use_program(ctx, i, shProg, new_prog, &ctx->Shader); + _mesa_use_program(ctx, i, shProg, new_prog, &ctx->Shader); } _mesa_active_program(ctx, shProg, "glUseProgram"); } @@ -1350,12 +1573,27 @@ validate_program(struct gl_context *ctx, GLuint program) } +void GLAPIENTRY +_mesa_AttachObjectARB_no_error(GLhandleARB program, GLhandleARB shader) +{ + GET_CURRENT_CONTEXT(ctx); + attach_shader_no_error(ctx, program, shader); +} + void GLAPIENTRY _mesa_AttachObjectARB(GLhandleARB program, GLhandleARB shader) { GET_CURRENT_CONTEXT(ctx); - attach_shader(ctx, program, shader); + attach_shader_err(ctx, program, shader, "glAttachObjectARB"); +} + + +void GLAPIENTRY +_mesa_AttachShader_no_error(GLuint program, GLuint shader) +{ + GET_CURRENT_CONTEXT(ctx); + attach_shader_no_error(ctx, program, shader); } @@ -1363,7 +1601,7 @@ void GLAPIENTRY _mesa_AttachShader(GLuint program, GLuint shader) { GET_CURRENT_CONTEXT(ctx); - attach_shader(ctx, program, shader); + attach_shader_err(ctx, program, shader, "glAttachShader"); } @@ -1378,12 +1616,30 @@ _mesa_CompileShader(GLuint shaderObj) } +GLuint GLAPIENTRY +_mesa_CreateShader_no_error(GLenum type) +{ + GET_CURRENT_CONTEXT(ctx); + return create_shader(ctx, type); +} + + GLuint GLAPIENTRY _mesa_CreateShader(GLenum type) { GET_CURRENT_CONTEXT(ctx); + if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glCreateShader %s\n", _mesa_enum_to_string(type)); + + return create_shader_err(ctx, type, "glCreateShader"); +} + + +GLhandleARB GLAPIENTRY +_mesa_CreateShaderObjectARB_no_error(GLenum type) +{ + GET_CURRENT_CONTEXT(ctx); return create_shader(ctx, type); } @@ -1392,7 +1648,7 @@ GLhandleARB GLAPIENTRY _mesa_CreateShaderObjectARB(GLenum type) { GET_CURRENT_CONTEXT(ctx); - return create_shader(ctx, type); + return create_shader_err(ctx, type, "glCreateShaderObjectARB"); } @@ -1460,11 +1716,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); } @@ -1472,7 +1744,7 @@ void GLAPIENTRY _mesa_DetachShader(GLuint program, GLuint shader) { GET_CURRENT_CONTEXT(ctx); - detach_shader(ctx, program, shader); + detach_shader_error(ctx, program, shader); } @@ -1481,7 +1753,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); } @@ -1490,7 +1762,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); } @@ -1615,14 +1887,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 @@ -1642,6 +1928,7 @@ generate_sha1(const char *source, char sha_str[64]) * following format: * * /_.glsl + * /_.arb */ static char * construct_name(const gl_shader_stage stage, const char *source, @@ -1652,15 +1939,17 @@ construct_name(const gl_shader_stage stage, const char *source, "VS", "TC", "TE", "GS", "FS", "CS", }; + const char *format = strncmp(source, "!!ARB", 5) ? "glsl" : "arb"; + generate_sha1(source, sha); - return ralloc_asprintf(NULL, "%s/%s_%s.glsl", path, types[stage], sha); + return ralloc_asprintf(NULL, "%s/%s_%s.%s", path, types[stage], sha, format); } /** * Write given shader source to a file in MESA_SHADER_DUMP_PATH. */ -static void -dump_shader(const gl_shader_stage stage, const char *source) +void +_mesa_dump_shader_source(const gl_shader_stage stage, const char *source) { static bool path_exists = true; char *dump_path; @@ -1693,8 +1982,8 @@ dump_shader(const gl_shader_stage stage, const char *source) * Read shader source code from a file. * Useful for debugging to override an app's shader. */ -static GLcharARB * -read_shader(const gl_shader_stage stage, const char *source) +GLcharARB * +_mesa_read_shader_source(const gl_shader_stage stage, const char *source) { char *read_path; static bool path_exists = true; @@ -1744,23 +2033,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); } /* @@ -1774,7 +2066,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)"); @@ -1815,23 +2107,41 @@ _mesa_ShaderSource(GLuint shaderObj, GLsizei count, /* Dump original shader source to MESA_SHADER_DUMP_PATH and replace * if corresponding entry found from MESA_SHADER_READ_PATH. */ - dump_shader(sh->Stage, source); + _mesa_dump_shader_source(sh->Stage, source); - replacement = read_shader(sh->Stage, source); + replacement = _mesa_read_shader_source(sh->Stage, source); if (replacement) { free(source); source = replacement; } #endif /* ENABLE_SHADER_CACHE */ - shader_source(sh, source); + set_shader_source(sh, source); free(offsets); } void GLAPIENTRY -_mesa_UseProgram(GLuint program) +_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) { GET_CURRENT_CONTEXT(ctx); struct gl_shader_program *shProg = NULL; @@ -1839,26 +2149,33 @@ _mesa_UseProgram(GLuint program) if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glUseProgram %u\n", program); - if (_mesa_is_xfb_active_and_unpaused(ctx)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glUseProgram(transform feedback active)"); - return; - } - - if (program) { - shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram"); - if (!shProg) { - return; + if (no_error) { + if (program) { + shProg = _mesa_lookup_shader_program(ctx, program); } - if (!shProg->data->LinkStatus) { + } else { + if (_mesa_is_xfb_active_and_unpaused(ctx)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glUseProgram(program %u not linked)", program); + "glUseProgram(transform feedback active)"); return; } - /* debug code */ - if (ctx->_Shader->Flags & GLSL_USE_PROG) { - print_shader_info(shProg); + if (program) { + shProg = + _mesa_lookup_shader_program_err(ctx, program, "glUseProgram"); + if (!shProg) + return; + + if (!shProg->data->LinkStatus) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glUseProgram(program %u not linked)", program); + return; + } + + /* debug code */ + if (ctx->_Shader->Flags & GLSL_USE_PROG) { + print_shader_info(shProg); + } } } @@ -1871,7 +2188,7 @@ _mesa_UseProgram(GLuint program) * object (section 2.14.PPO), the program bound to the appropriate * stage of the pipeline object is considered current." */ - if (program) { + if (shProg) { /* Attach shader state to the binding point */ _mesa_reference_pipeline_object(ctx, &ctx->_Shader, &ctx->Shader); /* Update the program */ @@ -1880,12 +2197,32 @@ _mesa_UseProgram(GLuint program) /* Must be done first: detach the progam */ _mesa_use_shader_program(ctx, shProg); /* Unattach shader_state binding point */ - _mesa_reference_pipeline_object(ctx, &ctx->_Shader, ctx->Pipeline.Default); + _mesa_reference_pipeline_object(ctx, &ctx->_Shader, + ctx->Pipeline.Default); /* If a pipeline was bound, rebind it */ if (ctx->Pipeline.Current) { - _mesa_BindProgramPipeline(ctx->Pipeline.Current->Name); + if (no_error) + _mesa_BindProgramPipeline_no_error(ctx->Pipeline.Current->Name); + else + _mesa_BindProgramPipeline(ctx->Pipeline.Current->Name); } } + + _mesa_update_vertex_processing_mode(ctx); +} + + +void GLAPIENTRY +_mesa_UseProgram_no_error(GLuint program) +{ + use_program(program, true); +} + + +void GLAPIENTRY +_mesa_UseProgram(GLuint program) +{ + use_program(program, false); } @@ -1958,7 +2295,12 @@ _mesa_GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, void GLAPIENTRY _mesa_ReleaseShaderCompiler(void) { - _mesa_destroy_shader_compiler_caches(); + GET_CURRENT_CONTEXT(ctx); + + if (ctx->shader_builtin_ref) { + _mesa_glsl_builtin_functions_decref(); + ctx->shader_builtin_ref = false; + } } @@ -1970,9 +2312,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: @@ -1986,6 +2326,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)"); } @@ -2032,12 +2403,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 @@ -2051,8 +2425,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: * @@ -2064,34 +2438,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 @@ -2107,7 +2479,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; } @@ -2122,7 +2494,7 @@ _mesa_ProgramParameteri(GLuint program, GLenum pname, GLint value) * will not be in effect until the next time LinkProgram or * ProgramBinary has been called successfully." * - * The resloution of issue 9 in the extension spec also says: + * The resolution of issue 9 in the extension spec also says: * * "The application may use the PROGRAM_BINARY_RETRIEVABLE_HINT hint * to indicate to the GL implementation that this program will @@ -2131,22 +2503,24 @@ _mesa_ProgramParameteri(GLuint program, GLenum pname, GLint value) * changes made to the program before being saved such that when it * is loaded again a recompile can be avoided." */ - shProg->BinaryRetreivableHint = value; + shProg->BinaryRetrievableHintPending = value; return; case GL_PROGRAM_SEPARABLE: /* 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; } @@ -2159,12 +2533,59 @@ 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, struct gl_pipeline_object *shTarget) { - use_program(ctx, stage, shProg, prog, shTarget); + struct gl_program **target; + + target = &shTarget->CurrentProgram[stage]; + if (prog) { + _mesa_program_init_subroutine_defaults(ctx, prog); + } + + if (*target != prog) { + /* Program is current, flush it */ + if (shTarget == ctx->_Shader) { + FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS); + } + + _mesa_reference_shader_program(ctx, + &shTarget->ReferencedPrograms[stage], + shProg); + _mesa_reference_program(ctx, target, prog); + _mesa_update_allow_draw_out_of_order(ctx); + if (stage == MESA_SHADER_VERTEX) + _mesa_update_vertex_processing_mode(ctx); + return; + } + } @@ -2214,7 +2635,7 @@ _mesa_CreateShaderProgramv(GLenum type, GLsizei count, { GET_CURRENT_CONTEXT(ctx); - const GLuint shader = create_shader(ctx, type); + const GLuint shader = create_shader_err(ctx, type, "glCreateShaderProgramv"); GLuint program = 0; /* @@ -2243,15 +2664,15 @@ _mesa_CreateShaderProgramv(GLenum type, GLsizei count, get_shaderiv(ctx, shader, GL_COMPILE_STATUS, &compiled); if (compiled) { - attach_shader(ctx, program, shader); + 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 } @@ -2269,6 +2690,15 @@ _mesa_CreateShaderProgramv(GLenum type, GLsizei count, /** * For GL_ARB_tessellation_shader */ +void GLAPIENTRY +_mesa_PatchParameteri_no_error(GLenum pname, GLint value) +{ + GET_CURRENT_CONTEXT(ctx); + FLUSH_VERTICES(ctx, 0); + ctx->TessCtrlProgram.patch_vertices = value; +} + + extern void GLAPIENTRY _mesa_PatchParameteri(GLenum pname, GLint value) { @@ -2289,6 +2719,7 @@ _mesa_PatchParameteri(GLenum pname, GLint value) return; } + FLUSH_VERTICES(ctx, 0); ctx->TessCtrlProgram.patch_vertices = value; } @@ -2335,11 +2766,6 @@ _mesa_GetSubroutineUniformLocation(GLuint program, GLenum shadertype, GLenum resource_type; gl_shader_stage stage; - if (!_mesa_has_ARB_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; @@ -2370,11 +2796,6 @@ _mesa_GetSubroutineIndex(GLuint program, GLenum shadertype, GLenum resource_type; gl_shader_stage stage; - if (!_mesa_has_ARB_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; @@ -2414,11 +2835,6 @@ _mesa_GetActiveSubroutineUniformiv(GLuint program, GLenum shadertype, GLenum resource_type; int count, i, j; - if (!_mesa_has_ARB_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; @@ -2501,11 +2917,6 @@ _mesa_GetActiveSubroutineUniformName(GLuint program, GLenum shadertype, GLenum resource_type; gl_shader_stage stage; - if (!_mesa_has_ARB_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; @@ -2540,11 +2951,6 @@ _mesa_GetActiveSubroutineName(GLuint program, GLenum shadertype, GLenum resource_type; gl_shader_stage stage; - if (!_mesa_has_ARB_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; @@ -2574,11 +2980,6 @@ _mesa_UniformSubroutinesuiv(GLenum shadertype, GLsizei count, gl_shader_stage stage; int i; - if (!_mesa_has_ARB_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; @@ -2597,6 +2998,7 @@ _mesa_UniformSubroutinesuiv(GLenum shadertype, GLsizei count, } i = 0; + bool flushed = false; do { struct gl_uniform_storage *uni = p->sh.SubroutineUniformRemapTable[i]; if (uni == NULL) { @@ -2604,6 +3006,11 @@ _mesa_UniformSubroutinesuiv(GLenum shadertype, GLsizei count, continue; } + if (!flushed) { + _mesa_flush_vertices_for_uniforms(ctx, uni); + flushed = true; + } + int uni_count = uni->array_elements ? uni->array_elements : 1; int j, k, f; @@ -2636,8 +3043,6 @@ _mesa_UniformSubroutinesuiv(GLenum shadertype, GLsizei count, } i += uni_count; } while(i < count); - - FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS); } @@ -2649,11 +3054,6 @@ _mesa_GetUniformSubroutineuiv(GLenum shadertype, GLint location, const char *api_name = "glGetUniformSubroutineuiv"; gl_shader_stage stage; - if (!_mesa_has_ARB_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; @@ -2685,11 +3085,6 @@ _mesa_GetProgramStageiv(GLuint program, GLenum shadertype, struct gl_linked_shader *sh; gl_shader_stage stage; - if (!_mesa_has_ARB_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; @@ -2781,6 +3176,533 @@ _mesa_GetProgramStageiv(GLuint program, GLenum shadertype, } } +/* This is simple list entry that will be used to hold a list of string + * tokens of a parsed shader include path. + */ +struct sh_incl_path_entry +{ + struct sh_incl_path_entry *next; + struct sh_incl_path_entry *prev; + + char *path; +}; + +/* Nodes of the shader include tree */ +struct sh_incl_path_ht_entry +{ + struct hash_table *path; + char *shader_source; +}; + +struct shader_includes { + /* Array to hold include paths given to glCompileShaderIncludeARB() */ + struct sh_incl_path_entry **include_paths; + size_t num_include_paths; + size_t relative_path_cursor; + + /* Root hash table holding the shader include tree */ + struct hash_table *shader_include_tree; +}; + +void +_mesa_init_shader_includes(struct gl_shared_state *shared) +{ + shared->ShaderIncludes = calloc(1, sizeof(struct shader_includes)); + shared->ShaderIncludes->shader_include_tree = + _mesa_hash_table_create(NULL, _mesa_hash_string, + _mesa_key_string_equal); +} + +size_t +_mesa_get_shader_include_cursor(struct gl_shared_state *shared) +{ + return shared->ShaderIncludes->relative_path_cursor; +} + +void +_mesa_set_shader_include_cursor(struct gl_shared_state *shared, size_t cursor) +{ + shared->ShaderIncludes->relative_path_cursor = cursor; +} + +static void +destroy_shader_include(struct hash_entry *entry) +{ + struct sh_incl_path_ht_entry *sh_incl_ht_entry = + (struct sh_incl_path_ht_entry *) entry->data; + + _mesa_hash_table_destroy(sh_incl_ht_entry->path, destroy_shader_include); + free(sh_incl_ht_entry->shader_source); + free(sh_incl_ht_entry); +} + +void +_mesa_destroy_shader_includes(struct gl_shared_state *shared) +{ + _mesa_hash_table_destroy(shared->ShaderIncludes->shader_include_tree, + destroy_shader_include); + free(shared->ShaderIncludes); +} + +static bool +valid_path_format(const char *str, bool relative_path) +{ + int i = 0; + + if (!str[i] || (!relative_path && str[i] != '/')) + return false; + + i++; + + while (str[i]) { + const char c = str[i++]; + if (('A' <= c && c <= 'Z') || + ('a' <= c && c <= 'z') || + ('0' <= c && c <= '9')) + continue; + + if (c == '/') { + if (str[i - 2] == '/') + return false; + + continue; + } + + if (strchr("^. _+*%[](){}|&~=!:;,?-", c) == NULL) + return false; + } + + if (str[i - 1] == '/') + return false; + + return true; +} + + +static bool +validate_and_tokenise_sh_incl(struct gl_context *ctx, + void *mem_ctx, + struct sh_incl_path_entry **path_list, + char *full_path, bool error_check) +{ + bool relative_path = ctx->Shared->ShaderIncludes->num_include_paths; + + if (!valid_path_format(full_path, relative_path)) { + if (error_check) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glNamedStringARB(invalid name %s)", full_path); + } + return false; + } + + char *save_ptr = NULL; + char *path_str = strtok_r(full_path, "/", &save_ptr); + + *path_list = rzalloc(mem_ctx, struct sh_incl_path_entry); + + make_empty_list(*path_list); + + while (path_str != NULL) { + if (strlen(path_str) == 0) { + if (error_check) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glNamedStringARB(invalid name %s)", full_path); + } + + return false; + } + + if (strcmp(path_str, ".") == 0) { + /* Do nothing */ + } else if (strcmp(path_str, "..") == 0) { + struct sh_incl_path_entry *last = last_elem(*path_list); + remove_from_list(last); + } else { + struct sh_incl_path_entry *path = + rzalloc(mem_ctx, struct sh_incl_path_entry); + + path->path = strdup(path_str); + insert_at_tail(*path_list, path); + } + + path_str = strtok_r(NULL, "/", &save_ptr); + } + + return true; +} + +static struct sh_incl_path_ht_entry * +lookup_shader_include(struct gl_context *ctx, char *path, + bool error_check) +{ + void *mem_ctx = ralloc_context(NULL); + struct sh_incl_path_entry *path_list; + + if (!validate_and_tokenise_sh_incl(ctx, mem_ctx, &path_list, path, + error_check)) { + ralloc_free(mem_ctx); + return NULL; + } + + struct sh_incl_path_ht_entry *sh_incl_ht_entry = NULL; + struct hash_table *path_ht = + ctx->Shared->ShaderIncludes->shader_include_tree; + + size_t count = ctx->Shared->ShaderIncludes->num_include_paths; + bool relative_path = path[0] != '/'; + + size_t i = ctx->Shared->ShaderIncludes->relative_path_cursor; + bool use_cursor = ctx->Shared->ShaderIncludes->relative_path_cursor; + + do { + struct sh_incl_path_entry *entry; + + if (relative_path) { +next_relative_path: + { + struct sh_incl_path_entry *rel_path_list = + ctx->Shared->ShaderIncludes->include_paths[i]; + foreach(entry, rel_path_list) { + struct hash_entry *ht_entry = + _mesa_hash_table_search(path_ht, entry->path); + + if (!ht_entry) { + /* Reset search path and skip to the next include path */ + path_ht = ctx->Shared->ShaderIncludes->shader_include_tree; + sh_incl_ht_entry = NULL; + if (use_cursor) { + i = 0; + use_cursor = false; + + goto next_relative_path; + } + i++; + if (i < count) + goto next_relative_path; + else + break; + } else { + sh_incl_ht_entry = + (struct sh_incl_path_ht_entry *) ht_entry->data; + } + + path_ht = sh_incl_ht_entry->path; + } + } + } + + foreach(entry, path_list) { + struct hash_entry *ht_entry = + _mesa_hash_table_search(path_ht, entry->path); + + if (!ht_entry) { + /* Reset search path and skip to the next include path */ + path_ht = ctx->Shared->ShaderIncludes->shader_include_tree; + sh_incl_ht_entry = NULL; + if (use_cursor) { + i = 0; + use_cursor = false; + + break; + } + i++; + break; + } else { + + sh_incl_ht_entry = + (struct sh_incl_path_ht_entry *) ht_entry->data; + } + + path_ht = sh_incl_ht_entry->path; + } + + if (i < count && + (sh_incl_ht_entry == NULL || !sh_incl_ht_entry->shader_source)) + continue; + + /* If we get here then we have found a matching path or exahusted our + * relative search paths. + */ + ctx->Shared->ShaderIncludes->relative_path_cursor = i; + break; + } while (i < count); + + ralloc_free(mem_ctx); + + return sh_incl_ht_entry; +} + +const char * +_mesa_lookup_shader_include(struct gl_context *ctx, char *path, + bool error_check) +{ + struct sh_incl_path_ht_entry *shader_include = + lookup_shader_include(ctx, path, error_check); + + return shader_include ? shader_include->shader_source : NULL; +} + +static char * +copy_string(struct gl_context *ctx, const char *str, int str_len, + const char *caller) +{ + if (!str) { + _mesa_error(ctx, GL_INVALID_VALUE, "%s(NULL string)", caller); + return NULL; + } + + char *cp; + if (str_len == -1) + cp = strdup(str); + else { + cp = calloc(sizeof(char), str_len + 1); + memcpy(cp, str, str_len); + } + + return cp; +} + +GLvoid GLAPIENTRY +_mesa_NamedStringARB(GLenum type, GLint namelen, const GLchar *name, + GLint stringlen, const GLchar *string) +{ + GET_CURRENT_CONTEXT(ctx); + const char *caller = "glNamedStringARB"; + + if (type != GL_SHADER_INCLUDE_ARB) { + _mesa_error(ctx, GL_INVALID_VALUE, "%s(invalid type)", caller); + return; + } + + char *name_cp = copy_string(ctx, name, namelen, caller); + char *string_cp = copy_string(ctx, string, stringlen, caller); + if (!name_cp || !string_cp) { + free(string_cp); + free(name_cp); + return; + } + + void *mem_ctx = ralloc_context(NULL); + struct sh_incl_path_entry *path_list; + + if (!validate_and_tokenise_sh_incl(ctx, mem_ctx, &path_list, name_cp, + true)) { + free(string_cp); + free(name_cp); + ralloc_free(mem_ctx); + return; + } + + mtx_lock(&ctx->Shared->ShaderIncludeMutex); + + struct hash_table *path_ht = + ctx->Shared->ShaderIncludes->shader_include_tree; + + struct sh_incl_path_entry *entry; + foreach(entry, path_list) { + struct hash_entry *ht_entry = + _mesa_hash_table_search(path_ht, entry->path); + + struct sh_incl_path_ht_entry *sh_incl_ht_entry; + if (!ht_entry) { + sh_incl_ht_entry = calloc(1, sizeof(struct sh_incl_path_ht_entry)); + sh_incl_ht_entry->path = + _mesa_hash_table_create(NULL, _mesa_hash_string, + _mesa_key_string_equal); + _mesa_hash_table_insert(path_ht, entry->path, sh_incl_ht_entry); + } else { + sh_incl_ht_entry = (struct sh_incl_path_ht_entry *) ht_entry->data; + } + + path_ht = sh_incl_ht_entry->path; + + if (last_elem(path_list) == entry) { + free(sh_incl_ht_entry->shader_source); + sh_incl_ht_entry->shader_source = string_cp; + } + } + + mtx_unlock(&ctx->Shared->ShaderIncludeMutex); + + free(name_cp); + ralloc_free(mem_ctx); +} + +GLvoid GLAPIENTRY +_mesa_DeleteNamedStringARB(GLint namelen, const GLchar *name) +{ + GET_CURRENT_CONTEXT(ctx); + const char *caller = "glDeleteNamedStringARB"; + + char *name_cp = copy_string(ctx, name, namelen, caller); + if (!name_cp) + return; + + struct sh_incl_path_ht_entry *shader_include = + lookup_shader_include(ctx, name_cp, true); + + if (!shader_include) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(no string associated with path %s)", caller, name_cp); + free(name_cp); + return; + } + + mtx_lock(&ctx->Shared->ShaderIncludeMutex); + + free(shader_include->shader_source); + shader_include->shader_source = NULL; + + mtx_unlock(&ctx->Shared->ShaderIncludeMutex); + + free(name_cp); +} + +GLvoid GLAPIENTRY +_mesa_CompileShaderIncludeARB(GLuint shader, GLsizei count, + const GLchar* const *path, const GLint *length) +{ + GET_CURRENT_CONTEXT(ctx); + const char *caller = "glCompileShaderIncludeARB"; + + if (count > 0 && path == NULL) { + _mesa_error(ctx, GL_INVALID_VALUE, "%s(count > 0 && path == NULL)", + caller); + return; + } + + void *mem_ctx = ralloc_context(NULL); + + mtx_lock(&ctx->Shared->ShaderIncludeMutex); + + ctx->Shared->ShaderIncludes->include_paths = + ralloc_array_size(mem_ctx, sizeof(struct sh_incl_path_entry *), count); + + for (size_t i = 0; i < count; i++) { + char *path_cp = copy_string(ctx, path[i], length ? length[i] : -1, + caller); + if (!path_cp) { + goto exit; + } + + struct sh_incl_path_entry *path_list; + + if (!validate_and_tokenise_sh_incl(ctx, mem_ctx, &path_list, path_cp, + true)) { + free(path_cp); + goto exit; + } + + ctx->Shared->ShaderIncludes->include_paths[i] = path_list; + + free(path_cp); + } + + /* We must set this *after* all calls to validate_and_tokenise_sh_incl() + * are done as we use this to decide if we need to check the start of the + * path for a '/' + */ + ctx->Shared->ShaderIncludes->num_include_paths = count; + + struct gl_shader *sh = _mesa_lookup_shader(ctx, shader); + if (!sh) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(shader)", caller); + goto exit; + } + + _mesa_compile_shader(ctx, sh); + +exit: + ctx->Shared->ShaderIncludes->num_include_paths = 0; + ctx->Shared->ShaderIncludes->relative_path_cursor = 0; + ctx->Shared->ShaderIncludes->include_paths = NULL; + + mtx_unlock(&ctx->Shared->ShaderIncludeMutex); + + ralloc_free(mem_ctx); +} + +GLboolean GLAPIENTRY +_mesa_IsNamedStringARB(GLint namelen, const GLchar *name) +{ + GET_CURRENT_CONTEXT(ctx); + + if (!name) + return false; + + char *name_cp = copy_string(ctx, name, namelen, ""); + + const char *source = _mesa_lookup_shader_include(ctx, name_cp, false); + free(name_cp); + + if (!source) + return false; + + return true; +} + +GLvoid GLAPIENTRY +_mesa_GetNamedStringARB(GLint namelen, const GLchar *name, GLsizei bufSize, + GLint *stringlen, GLchar *string) +{ + GET_CURRENT_CONTEXT(ctx); + const char *caller = "glGetNamedStringARB"; + + char *name_cp = copy_string(ctx, name, namelen, caller); + if (!name_cp) + return; + + const char *source = _mesa_lookup_shader_include(ctx, name_cp, true); + if (!source) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(no string associated with path %s)", caller, name_cp); + free(name_cp); + return; + } + + size_t size = MIN2(strlen(source), bufSize - 1); + memcpy(string, source, size); + string[size] = '\0'; + + *stringlen = size; + + free(name_cp); +} + +GLvoid GLAPIENTRY +_mesa_GetNamedStringivARB(GLint namelen, const GLchar *name, + GLenum pname, GLint *params) +{ + GET_CURRENT_CONTEXT(ctx); + const char *caller = "glGetNamedStringivARB"; + + char *name_cp = copy_string(ctx, name, namelen, caller); + if (!name_cp) + return; + + const char *source = _mesa_lookup_shader_include(ctx, name_cp, true); + if (!source) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(no string associated with path %s)", caller, name_cp); + free(name_cp); + return; + } + + switch (pname) { + case GL_NAMED_STRING_LENGTH_ARB: + *params = strlen(source) + 1; + break; + case GL_NAMED_STRING_TYPE_ARB: + *params = GL_SHADER_INCLUDE_ARB; + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname)", caller); + break; + } + + free(name_cp); +} + static int find_compat_subroutine(struct gl_program *p, const struct glsl_type *type) {