X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Fshaderapi.c;h=a988f41697bb1b16e743d282cdd4339f4d4cd15a;hb=886399694021d013908106cdccab66fda275ae75;hp=cc001ba2bcf678121cf25c270fa8fbad903dd7e9;hpb=1948880720a631f959c6fa7f5bc533f26619a31a;p=mesa.git diff --git a/src/mesa/main/shaderapi.c b/src/mesa/main/shaderapi.c index cc001ba2bcf..16d9f1e6486 100644 --- a/src/mesa/main/shaderapi.c +++ b/src/mesa/main/shaderapi.c @@ -37,6 +37,7 @@ */ +#include #include "main/glheader.h" #include "main/context.h" #include "main/dispatch.h" @@ -48,20 +49,17 @@ #include "main/shaderobj.h" #include "main/transformfeedback.h" #include "main/uniforms.h" +#include "compiler/glsl/glsl_parser_extras.h" +#include "compiler/glsl/ir.h" +#include "compiler/glsl/ir_uniform.h" +#include "compiler/glsl/program.h" #include "program/program.h" #include "program/prog_print.h" #include "program/prog_parameter.h" #include "util/ralloc.h" #include "util/hash_table.h" -#include -#include "../glsl/glsl_parser_extras.h" -#include "../glsl/ir.h" -#include "../glsl/ir_uniform.h" -#include "../glsl/program.h" - -/** Define this to enable shader substitution (see below) */ -#define SHADER_SUBST 0 - +#include "util/mesa-sha1.h" +#include "util/crc32.h" /** * Return mask of GLSL_x flags by examining the MESA_GLSL env var. @@ -79,14 +77,14 @@ _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")) flags |= GLSL_NOP_VERT; if (strstr(env, "nopfrag")) flags |= GLSL_NOP_FRAG; - if (strstr(env, "nopt")) - flags |= GLSL_NO_OPT; - else if (strstr(env, "opt")) - flags |= GLSL_OPT; if (strstr(env, "uniform")) flags |= GLSL_UNIFORMS; if (strstr(env, "useprog")) @@ -98,6 +96,22 @@ _mesa_get_shader_flags(void) return flags; } +/** + * Memoized version of getenv("MESA_SHADER_CAPTURE_PATH"). + */ +const char * +_mesa_get_shader_capture_path(void) +{ + static bool read_env_var = false; + static const char *path = NULL; + + if (!read_env_var) { + path = getenv("MESA_SHADER_CAPTURE_PATH"); + read_env_var = true; + } + + return path; +} /** * Initialize context's shader state. @@ -110,6 +124,7 @@ _mesa_init_shader_state(struct gl_context *ctx) */ struct gl_shader_compiler_options options; gl_shader_stage sh; + int i; memset(&options, 0, sizeof(options)); options.MaxUnrollIterations = 32; @@ -125,7 +140,11 @@ _mesa_init_shader_state(struct gl_context *ctx) /* Extended for ARB_separate_shader_objects */ ctx->Shader.RefCount = 1; - mtx_init(&ctx->Shader.Mutex, mtx_plain); + ctx->TessCtrlProgram.patch_vertices = 3; + for (i = 0; i < 4; ++i) + ctx->TessCtrlProgram.patch_default_outer_level[i] = 1.0; + for (i = 0; i < 2; ++i) + ctx->TessCtrlProgram.patch_default_inner_level[i] = 1.0; } @@ -135,20 +154,15 @@ _mesa_init_shader_state(struct gl_context *ctx) void _mesa_free_shader_state(struct gl_context *ctx) { - int i; - for (i = 0; i < MESA_SHADER_STAGES; i++) { - _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram[i], - NULL); + 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._CurrentFragmentProgram, - NULL); _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, NULL); /* Extended for ARB_separate_shader_objects */ _mesa_reference_pipeline_object(ctx, &ctx->_Shader, NULL); assert(ctx->Shader.RefCount == 1); - mtx_destroy(&ctx->Shader.Mutex); } @@ -199,8 +213,11 @@ _mesa_validate_shader_target(const struct gl_context *ctx, GLenum type) return ctx == NULL || ctx->Extensions.ARB_vertex_shader; case GL_GEOMETRY_SHADER_ARB: return ctx == NULL || _mesa_has_geometry_shaders(ctx); + case GL_TESS_CONTROL_SHADER: + case GL_TESS_EVALUATION_SHADER: + return ctx == NULL || _mesa_has_tessellation(ctx); case GL_COMPUTE_SHADER: - return ctx == NULL || ctx->Extensions.ARB_compute_shader; + return ctx == NULL || _mesa_has_compute_shaders(ctx); default: return false; } @@ -227,7 +244,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; @@ -235,11 +272,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; } @@ -253,10 +290,10 @@ 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, caller); return; } else if (same_type_disallowed && - shProg->Shaders[i]->Type == sh->Type) { + shProg->Shaders[i]->Stage == sh->Stage) { /* Shader with the same type is already attached to this program, * OpenGL ES 2.0 and 3.0 specs say: * @@ -265,25 +302,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, 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) @@ -292,13 +329,17 @@ create_shader(struct gl_context *ctx, GLenum type) GLuint name; if (!_mesa_validate_shader_target(ctx, type)) { - _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(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 = ctx->Driver.NewShader(ctx, name, type); - _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh); + sh = _mesa_new_shader(name, _mesa_shader_enum_to_shader_stage(type)); + sh->Type = type; + _mesa_HashInsertLocked(ctx->Shared->ShaderObjects, name, sh); + _mesa_HashUnlockMutex(ctx->Shared->ShaderObjects); return name; } @@ -310,14 +351,18 @@ create_shader_program(struct gl_context *ctx) GLuint name; struct gl_shader_program *shProg; + _mesa_HashLockMutex(ctx->Shared->ShaderObjects); + name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1); - shProg = ctx->Driver.NewShaderProgram(name); + shProg = _mesa_new_shader_program(name); - _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg); + _mesa_HashInsertLocked(ctx->Shared->ShaderObjects, name, shProg); assert(shProg->RefCount == 1); + _mesa_HashUnlockMutex(ctx->Shared->ShaderObjects); + return name; } @@ -414,9 +459,11 @@ detach_shader(struct gl_context *ctx, GLuint program, GLuint shader) #ifdef DEBUG /* sanity check - make sure the new list's entries are sensible */ for (j = 0; j < shProg->NumShaders; j++) { - assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER || - shProg->Shaders[j]->Type == GL_GEOMETRY_SHADER || - shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER); + assert(shProg->Shaders[j]->Stage == MESA_SHADER_VERTEX || + shProg->Shaders[j]->Stage == MESA_SHADER_TESS_CTRL || + shProg->Shaders[j]->Stage == MESA_SHADER_TESS_EVAL || + shProg->Shaders[j]->Stage == MESA_SHADER_GEOMETRY || + shProg->Shaders[j]->Stage == MESA_SHADER_FRAGMENT); assert(shProg->Shaders[j]->RefCount > 0); } #endif @@ -499,7 +546,7 @@ get_handle(struct gl_context *ctx, GLenum pname) static bool check_gs_query(struct gl_context *ctx, const struct gl_shader_program *shProg) { - if (shProg->LinkStatus && + if (shProg->data->LinkStatus && shProg->_LinkedShaders[MESA_SHADER_GEOMETRY] != NULL) { return true; } @@ -510,6 +557,57 @@ check_gs_query(struct gl_context *ctx, const struct gl_shader_program *shProg) } +/** + * Check if a tessellation control shader query is valid at this time. + * If not, report an error and return false. + * + * From GL 4.0 section 6.1.12 (Shader and Program Queries): + * + * "If TESS_CONTROL_OUTPUT_VERTICES is queried for a program which has + * not been linked successfully, or which does not contain objects to + * form a tessellation control shader, then an INVALID_OPERATION error is + * generated." + */ +static bool +check_tcs_query(struct gl_context *ctx, const struct gl_shader_program *shProg) +{ + if (shProg->data->LinkStatus && + shProg->_LinkedShaders[MESA_SHADER_TESS_CTRL] != NULL) { + return true; + } + + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetProgramv(linked tessellation control shader required)"); + return false; +} + + +/** + * Check if a tessellation evaluation shader query is valid at this time. + * If not, report an error and return false. + * + * From GL 4.0 section 6.1.12 (Shader and Program Queries): + * + * "If any of the pname values in this paragraph are queried for a program + * which has not been linked successfully, or which does not contain + * objects to form a tessellation evaluation shader, then an + * INVALID_OPERATION error is generated." + * + */ +static bool +check_tes_query(struct gl_context *ctx, const struct gl_shader_program *shProg) +{ + if (shProg->data->LinkStatus && + shProg->_LinkedShaders[MESA_SHADER_TESS_EVAL] != NULL) { + return true; + } + + _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramv(linked tessellation " + "evaluation shader required)"); + return false; +} + + /** * glGetProgramiv() - get shader program state. * Note that this is for GLSL shader programs, not ARB vertex/fragment @@ -532,7 +630,8 @@ 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_is_desktop_gl(ctx) && ctx->Version >= 32; + const bool has_core_gs = _mesa_has_geometry_shaders(ctx); + const bool has_tess = _mesa_has_tessellation(ctx); /* Are uniform buffer objects available in this context? */ @@ -551,13 +650,14 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, *params = shProg->DeletePending; return; case GL_LINK_STATUS: - *params = shProg->LinkStatus; + *params = shProg->data->LinkStatus ? GL_TRUE : GL_FALSE; return; case GL_VALIDATE_STATUS: - *params = shProg->Validated; + *params = shProg->data->Validated; return; case GL_INFO_LOG_LENGTH: - *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0; + *params = (shProg->data->InfoLog && shProg->data->InfoLog[0] != '\0') ? + strlen(shProg->data->InfoLog) + 1 : 0; return; case GL_ATTACHED_SHADERS: *params = shProg->NumShaders; @@ -568,21 +668,31 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH: *params = _mesa_longest_attribute_name_length(shProg); return; - case GL_ACTIVE_UNIFORMS: - *params = shProg->NumUserUniformStorage - shProg->NumHiddenUniforms; + case GL_ACTIVE_UNIFORMS: { + unsigned i; + const unsigned num_uniforms = + shProg->data->NumUniformStorage - shProg->data->NumHiddenUniforms; + for (*params = 0, i = 0; i < num_uniforms; i++) { + if (!shProg->data->UniformStorage[i].is_shader_storage) + (*params)++; + } return; + } case GL_ACTIVE_UNIFORM_MAX_LENGTH: { unsigned i; GLint max_len = 0; const unsigned num_uniforms = - shProg->NumUserUniformStorage - shProg->NumHiddenUniforms; + shProg->data->NumUniformStorage - shProg->data->NumHiddenUniforms; for (i = 0; i < num_uniforms; i++) { + if (shProg->data->UniformStorage[i].is_shader_storage) + continue; + /* 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->UniformStorage[i].name) + 1 + - ((shProg->UniformStorage[i].array_elements != 0) ? 3 : 0); + const GLint len = strlen(shProg->data->UniformStorage[i].name) + 1 + + ((shProg->data->UniformStorage[i].array_elements != 0) ? 3 : 0); if (len > max_len) max_len = len; @@ -623,26 +733,34 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, case GL_GEOMETRY_VERTICES_OUT: if (!has_core_gs) break; - if (check_gs_query(ctx, shProg)) - *params = shProg->Geom.VerticesOut; + if (check_gs_query(ctx, shProg)) { + *params = shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]-> + Program->info.gs.vertices_out; + } return; case GL_GEOMETRY_SHADER_INVOCATIONS: if (!has_core_gs || !ctx->Extensions.ARB_gpu_shader5) break; - if (check_gs_query(ctx, shProg)) - *params = shProg->Geom.Invocations; + 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) break; - if (check_gs_query(ctx, shProg)) - *params = shProg->Geom.InputType; + if (check_gs_query(ctx, shProg)) { + *params = shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]-> + Program->info.gs.input_primitive; + } return; case GL_GEOMETRY_OUTPUT_TYPE: if (!has_core_gs) break; - if (check_gs_query(ctx, shProg)) - *params = shProg->Geom.OutputType; + if (check_gs_query(ctx, shProg)) { + *params = shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]-> + Program->info.gs.output_primitive; + } return; case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH: { unsigned i; @@ -651,10 +769,10 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, if (!has_ubo) break; - for (i = 0; i < shProg->NumUniformBlocks; i++) { + for (i = 0; i < shProg->data->NumUniformBlocks; i++) { /* Add one for the terminating NUL character. */ - const GLint len = strlen(shProg->UniformBlocks[i].Name) + 1; + const GLint len = strlen(shProg->data->UniformBlocks[i].Name) + 1; if (len > max_len) max_len = len; @@ -667,7 +785,7 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, if (!has_ubo) break; - *params = shProg->NumUniformBlocks; + *params = shProg->data->NumUniformBlocks; return; case GL_PROGRAM_BINARY_RETRIEVABLE_HINT: /* This enum isn't part of the OES extension for OpenGL ES 2.0. It is @@ -688,13 +806,13 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, if (!ctx->Extensions.ARB_shader_atomic_counters) break; - *params = shProg->NumAtomicBuffers; + *params = shProg->data->NumAtomicBuffers; return; case GL_COMPUTE_WORK_GROUP_SIZE: { int i; - if (!_mesa_is_desktop_gl(ctx) || !ctx->Extensions.ARB_compute_shader) + if (!_mesa_has_compute_shaders(ctx)) break; - if (!shProg->LinkStatus) { + if (!shProg->data->LinkStatus) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramiv(program not " "linked)"); return; @@ -705,18 +823,76 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, return; } for (i = 0; i < 3; i++) - params[i] = shProg->Comp.LocalSize[i]; + params[i] = shProg->_LinkedShaders[MESA_SHADER_COMPUTE]-> + Program->info.cs.local_size[i]; return; } case GL_PROGRAM_SEPARABLE: - *params = shProg->SeparateShader; + /* If the program has not been linked, return initial value 0. */ + *params = (shProg->data->LinkStatus == linking_failure) ? 0 : shProg->SeparateShader; + return; + + /* ARB_tessellation_shader */ + case GL_TESS_CONTROL_OUTPUT_VERTICES: + if (!has_tess) + break; + if (check_tcs_query(ctx, shProg)) { + *params = shProg->_LinkedShaders[MESA_SHADER_TESS_CTRL]-> + Program->info.tess.tcs_vertices_out; + } + return; + case GL_TESS_GEN_MODE: + if (!has_tess) + break; + if (check_tes_query(ctx, shProg)) { + *params = shProg->_LinkedShaders[MESA_SHADER_TESS_EVAL]-> + Program->info.tess.primitive_mode; + } + return; + case GL_TESS_GEN_SPACING: + if (!has_tess) + break; + if (check_tes_query(ctx, shProg)) { + const struct gl_linked_shader *tes = + shProg->_LinkedShaders[MESA_SHADER_TESS_EVAL]; + switch (tes->Program->info.tess.spacing) { + case TESS_SPACING_EQUAL: + *params = GL_EQUAL; + break; + case TESS_SPACING_FRACTIONAL_ODD: + *params = GL_FRACTIONAL_ODD; + break; + case TESS_SPACING_FRACTIONAL_EVEN: + *params = GL_FRACTIONAL_EVEN; + break; + case TESS_SPACING_UNSPECIFIED: + *params = 0; + break; + } + } + return; + case GL_TESS_GEN_VERTEX_ORDER: + if (!has_tess) + break; + if (check_tes_query(ctx, shProg)) { + *params = shProg->_LinkedShaders[MESA_SHADER_TESS_EVAL]-> + Program->info.tess.ccw ? GL_CCW : GL_CW; + } + return; + case GL_TESS_GEN_POINT_MODE: + if (!has_tess) + break; + if (check_tes_query(ctx, shProg)) { + *params = shProg->_LinkedShaders[MESA_SHADER_TESS_EVAL]-> + Program->info.tess.point_mode ? GL_TRUE : GL_FALSE; + } return; default: break; } _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname=%s)", - _mesa_lookup_enum_by_nr(pname)); + _mesa_enum_to_string(pname)); } @@ -741,10 +917,11 @@ get_shaderiv(struct gl_context *ctx, GLuint name, GLenum pname, GLint *params) *params = shader->DeletePending; break; case GL_COMPILE_STATUS: - *params = shader->CompileStatus; + *params = shader->CompileStatus ? GL_TRUE : GL_FALSE; break; case GL_INFO_LOG_LENGTH: - *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0; + *params = (shader->InfoLog && shader->InfoLog[0] != '\0') ? + strlen(shader->InfoLog) + 1 : 0; break; case GL_SHADER_SOURCE_LENGTH: *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0; @@ -779,7 +956,7 @@ get_program_info_log(struct gl_context *ctx, GLuint program, GLsizei bufSize, return; } - _mesa_copy_string(infoLog, bufSize, length, shProg->InfoLog); + _mesa_copy_string(infoLog, bufSize, length, shProg->data->InfoLog); } @@ -836,20 +1013,24 @@ get_shader_source(struct gl_context *ctx, GLuint shader, GLsizei maxLength, * glShaderSource[ARB]. */ static void -shader_source(struct gl_context *ctx, GLuint shader, const GLchar *source) +shader_source(struct gl_shader *sh, const GLchar *source) { - struct gl_shader *sh; + assert(sh); - sh = _mesa_lookup_shader_err(ctx, shader, "glShaderSource"); - if (!sh) - return; + if (sh->CompileStatus == compile_skipped && !sh->FallbackSource) { + /* If shader was previously compiled back-up the source in case of cache + * fallback. + */ + sh->FallbackSource = sh->Source; + sh->Source = source; + } else { + /* free old shader source string and install new one */ + free((void *)sh->Source); + sh->Source = source; + } - /* free old shader source string and install new one */ - free((void *)sh->Source); - sh->Source = source; - sh->CompileStatus = GL_FALSE; #ifdef DEBUG - sh->SourceChecksum = _mesa_str_checksum(sh->Source); + sh->SourceChecksum = util_hash_crc32(sh->Source, strlen(sh->Source)); #endif } @@ -857,23 +1038,17 @@ shader_source(struct gl_context *ctx, GLuint shader, const GLchar *source) /** * Compile a shader. */ -static void -compile_shader(struct gl_context *ctx, GLuint shaderObj) +void +_mesa_compile_shader(struct gl_context *ctx, struct gl_shader *sh) { - struct gl_shader *sh; - struct gl_shader_compiler_options *options; - - sh = _mesa_lookup_shader_err(ctx, shaderObj, "glCompileShader"); if (!sh) return; - options = &ctx->Const.ShaderCompilerOptions[sh->Stage]; - 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 = GL_FALSE; + sh->CompileStatus = compile_failure; } else { if (ctx->_Shader->Flags & GLSL_DUMP) { _mesa_log("GLSL source for %s shader %d:\n", @@ -884,7 +1059,7 @@ compile_shader(struct gl_context *ctx, GLuint shaderObj) /* this call will set the shader->CompileStatus field to indicate if * compilation was successful. */ - _mesa_glsl_compile_shader(ctx, sh, false, false); + _mesa_glsl_compile_shader(ctx, sh, false, false, false); if (ctx->_Shader->Flags & GLSL_LOG) { _mesa_write_shader_to_file(sh); @@ -892,8 +1067,13 @@ compile_shader(struct gl_context *ctx, GLuint shaderObj) if (ctx->_Shader->Flags & GLSL_DUMP) { if (sh->CompileStatus) { - _mesa_log("GLSL IR for shader %d:\n", sh->Name); - _mesa_print_ir(_mesa_get_log_file(), sh->ir, NULL); + if (sh->ir) { + _mesa_log("GLSL IR for shader %d:\n", sh->Name); + _mesa_print_ir(_mesa_get_log_file(), sh->ir, NULL); + } else { + _mesa_log("No GLSL IR for shader %d (shader may be from " + "cache)\n", sh->Name); + } _mesa_log("\n\n"); } else { _mesa_log("GLSL shader %d failed to compile.\n", sh->Name); @@ -924,12 +1104,9 @@ compile_shader(struct gl_context *ctx, GLuint shaderObj) /** * Link a program's shaders. */ -static void -link_program(struct gl_context *ctx, GLuint program) +void +_mesa_link_program(struct gl_context *ctx, struct gl_shader_program *shProg) { - struct gl_shader_program *shProg; - - shProg = _mesa_lookup_shader_program_err(ctx, program, "glLinkProgram"); if (!shProg) return; @@ -944,14 +1121,72 @@ link_program(struct gl_context *ctx, GLuint program) return; } - FLUSH_VERTICES(ctx, _NEW_PROGRAM); + unsigned programs_in_use = 0; + if (ctx->_Shader) + for (unsigned stage = 0; stage < MESA_SHADER_STAGES; stage++) { + if (ctx->_Shader->CurrentProgram[stage] && + ctx->_Shader->CurrentProgram[stage]->Id == shProg->Name) { + programs_in_use |= 1 << stage; + } + } + FLUSH_VERTICES(ctx, 0); _mesa_glsl_link_shader(ctx, shProg); - if (shProg->LinkStatus == GL_FALSE && + /* From section 7.3 (Program Objects) of the OpenGL 4.5 spec: + * + * "If LinkProgram or ProgramBinary successfully re-links a program + * object that is active for any shader stage, then the newly generated + * executable code will be installed as part of the current rendering + * state for all shader stages where the program is active. + * Additionally, the newly generated executable code is made part of + * the state of any program pipeline for all stages where the program + * is attached." + */ + if (shProg->data->LinkStatus && programs_in_use) { + while (programs_in_use) { + const int stage = u_bit_scan(&programs_in_use); + + struct gl_program *prog = NULL; + if (shProg->_LinkedShaders[stage]) + prog = shProg->_LinkedShaders[stage]->Program; + + _mesa_use_program(ctx, stage, shProg, prog, ctx->_Shader); + } + } + + /* 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", + capture_path, shProg->Name); + file = fopen(filename, "w"); + if (file) { + fprintf(file, "[require]\nGLSL%s >= %u.%02u\n", + shProg->IsES ? " ES" : "", + shProg->data->Version / 100, shProg->data->Version % 100); + if (shProg->SeparateShader) + fprintf(file, "GL_ARB_separate_shader_objects\nSSO ENABLED\n"); + fprintf(file, "\n"); + + for (unsigned i = 0; i < shProg->NumShaders; i++) { + fprintf(file, "[%s shader]\n%s\n", + _mesa_shader_stage_to_string(shProg->Shaders[i]->Stage), + shProg->Shaders[i]->Source); + } + fclose(file); + } else { + _mesa_warning(ctx, "Failed to open %s", filename); + } + + ralloc_free(filename); + } + + 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->InfoLog); + shProg->Name, shProg->data->InfoLog); } /* debug code */ @@ -960,12 +1195,12 @@ link_program(struct gl_context *ctx, GLuint program) printf("Link %u shaders in program %u: %s\n", shProg->NumShaders, shProg->Name, - shProg->LinkStatus ? "Success" : "Failed"); + shProg->data->LinkStatus ? "Success" : "Failed"); for (i = 0; i < shProg->NumShaders; i++) { - printf(" shader %u, type 0x%x\n", + printf(" shader %u, stage %u\n", shProg->Shaders[i]->Name, - shProg->Shaders[i]->Type); + shProg->Shaders[i]->Stage); } } } @@ -981,10 +1216,16 @@ print_shader_info(const struct gl_shader_program *shProg) printf("Mesa: glUseProgram(%u)\n", shProg->Name); for (i = 0; i < shProg->NumShaders; i++) { +#ifdef DEBUG printf(" %s shader %u, checksum %u\n", _mesa_shader_stage_to_string(shProg->Shaders[i]->Stage), shProg->Shaders[i]->Name, shProg->Shaders[i]->SourceChecksum); +#else + printf(" %s shader %u\n", + _mesa_shader_stage_to_string(shProg->Shaders[i]->Stage), + shProg->Shaders[i]->Name); +#endif } if (shProg->_LinkedShaders[MESA_SHADER_VERTEX]) printf(" vert prog %u\n", @@ -995,6 +1236,12 @@ print_shader_info(const struct gl_shader_program *shProg) if (shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]) printf(" geom prog %u\n", shProg->_LinkedShaders[MESA_SHADER_GEOMETRY]->Program->Id); + if (shProg->_LinkedShaders[MESA_SHADER_TESS_CTRL]) + printf(" tesc prog %u\n", + shProg->_LinkedShaders[MESA_SHADER_TESS_CTRL]->Program->Id); + if (shProg->_LinkedShaders[MESA_SHADER_TESS_EVAL]) + printf(" tese prog %u\n", + shProg->_LinkedShaders[MESA_SHADER_TESS_EVAL]->Program->Id); } @@ -1005,7 +1252,7 @@ void _mesa_active_program(struct gl_context *ctx, struct gl_shader_program *shProg, const char *caller) { - if ((shProg != NULL) && !shProg->LinkStatus) { + if ((shProg != NULL) && !shProg->data->LinkStatus) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(program %u not linked)", caller, shProg->Name); return; @@ -1017,65 +1264,20 @@ _mesa_active_program(struct gl_context *ctx, struct gl_shader_program *shProg, } -static void -use_shader_program(struct gl_context *ctx, gl_shader_stage stage, - struct gl_shader_program *shProg, - struct gl_pipeline_object *shTarget) -{ - struct gl_shader_program **target; - - target = &shTarget->CurrentProgram[stage]; - if ((shProg != NULL) && (shProg->_LinkedShaders[stage] == NULL)) - shProg = NULL; - - if (*target != shProg) { - /* Program is current, flush it */ - if (shTarget == ctx->_Shader) { - FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS); - } - - /* If the shader is also bound as the current rendering shader, unbind - * it from that binding point as well. This ensures that the correct - * semantics of glDeleteProgram are maintained. - */ - switch (stage) { - case MESA_SHADER_VERTEX: - /* Empty for now. */ - break; - case MESA_SHADER_GEOMETRY: - /* Empty for now. */ - break; - case MESA_SHADER_COMPUTE: - /* Empty for now. */ - break; - case MESA_SHADER_FRAGMENT: - if (*target == ctx->_Shader->_CurrentFragmentProgram) { - _mesa_reference_shader_program(ctx, - &ctx->_Shader->_CurrentFragmentProgram, - NULL); - } - break; - } - - _mesa_reference_shader_program(ctx, target, shProg); - return; - } -} - - /** * Use the named shader program for subsequent rendering. */ void -_mesa_use_program(struct gl_context *ctx, struct gl_shader_program *shProg) +_mesa_use_shader_program(struct gl_context *ctx, + struct gl_shader_program *shProg) { - int i; - for (i = 0; i < MESA_SHADER_STAGES; i++) - use_shader_program(ctx, i, shProg, &ctx->Shader); + for (int i = 0; i < MESA_SHADER_STAGES; i++) { + struct gl_program *new_prog = NULL; + if (shProg && shProg->_LinkedShaders[i]) + new_prog = shProg->_LinkedShaders[i]->Program; + _mesa_use_program(ctx, i, shProg, new_prog, &ctx->Shader); + } _mesa_active_program(ctx, shProg, "glUseProgram"); - - if (ctx->Driver.UseProgram) - ctx->Driver.UseProgram(ctx, shProg); } @@ -1088,7 +1290,7 @@ static GLboolean validate_shader_program(const struct gl_shader_program *shProg, char *errMsg) { - if (!shProg->LinkStatus) { + if (!shProg->data->LinkStatus) { return GL_FALSE; } @@ -1132,23 +1334,38 @@ validate_program(struct gl_context *ctx, GLuint program) return; } - shProg->Validated = validate_shader_program(shProg, errMsg); - if (!shProg->Validated) { + shProg->data->Validated = validate_shader_program(shProg, errMsg); + if (!shProg->data->Validated) { /* update info log */ - if (shProg->InfoLog) { - ralloc_free(shProg->InfoLog); + if (shProg->data->InfoLog) { + ralloc_free(shProg->data->InfoLog); } - shProg->InfoLog = ralloc_strdup(shProg, errMsg); + shProg->data->InfoLog = ralloc_strdup(shProg->data, errMsg); } } +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); } @@ -1156,17 +1373,18 @@ void GLAPIENTRY _mesa_AttachShader(GLuint program, GLuint shader) { GET_CURRENT_CONTEXT(ctx); - attach_shader(ctx, program, shader); + attach_shader_err(ctx, program, shader, "glAttachShader"); } void GLAPIENTRY -_mesa_CompileShader(GLhandleARB shaderObj) +_mesa_CompileShader(GLuint shaderObj) { GET_CURRENT_CONTEXT(ctx); if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "glCompileShader %u\n", shaderObj); - compile_shader(ctx, shaderObj); + _mesa_compile_shader(ctx, _mesa_lookup_shader_err(ctx, shaderObj, + "glCompileShader")); } @@ -1175,7 +1393,7 @@ _mesa_CreateShader(GLenum type) { GET_CURRENT_CONTEXT(ctx); if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glCreateShader %s\n", _mesa_lookup_enum_by_nr(type)); + _mesa_debug(ctx, "glCreateShader %s\n", _mesa_enum_to_string(type)); return create_shader(ctx, type); } @@ -1211,7 +1429,7 @@ _mesa_DeleteObjectARB(GLhandleARB obj) { if (MESA_VERBOSE & VERBOSE_API) { GET_CURRENT_CONTEXT(ctx); - _mesa_debug(ctx, "glDeleteObjectARB(%u)\n", obj); + _mesa_debug(ctx, "glDeleteObjectARB(%lu)\n", (unsigned long)obj); } if (obj) { @@ -1334,7 +1552,7 @@ void GLAPIENTRY _mesa_GetObjectParameterfvARB(GLhandleARB object, GLenum pname, GLfloat *params) { - GLint iparams[1]; /* XXX is one element enough? */ + GLint iparams[1] = {0}; /* XXX is one element enough? */ _mesa_GetObjectParameterivARB(object, pname, iparams); params[0] = (GLfloat) iparams[0]; } @@ -1375,8 +1593,8 @@ _mesa_GetShaderInfoLog(GLuint shader, GLsizei bufSize, void GLAPIENTRY -_mesa_GetShaderSource(GLhandleARB shader, GLsizei maxLength, - GLsizei *length, GLcharARB *sourceOut) +_mesa_GetShaderSource(GLuint shader, GLsizei maxLength, + GLsizei *length, GLchar *sourceOut) { GET_CURRENT_CONTEXT(ctx); get_shader_source(ctx, shader, maxLength, length, sourceOut); @@ -1408,30 +1626,107 @@ _mesa_IsShader(GLuint name) void GLAPIENTRY -_mesa_LinkProgram(GLhandleARB programObj) +_mesa_LinkProgram(GLuint programObj) { GET_CURRENT_CONTEXT(ctx); - link_program(ctx, programObj); + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glLinkProgram %u\n", programObj); + _mesa_link_program(ctx, _mesa_lookup_shader_program_err(ctx, programObj, + "glLinkProgram")); +} + +#ifdef ENABLE_SHADER_CACHE +/** + * Generate a SHA-1 hash value string for given source string. + */ +static void +generate_sha1(const char *source, char sha_str[64]) +{ + unsigned char sha[20]; + _mesa_sha1_compute(source, strlen(source), sha); + _mesa_sha1_format(sha_str, sha); +} + +/** + * Construct a full path for shader replacement functionality using + * following format: + * + * /_.glsl + */ +static char * +construct_name(const gl_shader_stage stage, const char *source, + const char *path) +{ + char sha[64]; + static const char *types[] = { + "VS", "TC", "TE", "GS", "FS", "CS", + }; + + generate_sha1(source, sha); + return ralloc_asprintf(NULL, "%s/%s_%s.glsl", path, types[stage], sha); } +/** + * Write given shader source to a file in MESA_SHADER_DUMP_PATH. + */ +static void +dump_shader(const gl_shader_stage stage, const char *source) +{ + static bool path_exists = true; + char *dump_path; + FILE *f; + + if (!path_exists) + return; + + dump_path = getenv("MESA_SHADER_DUMP_PATH"); + if (!dump_path) { + path_exists = false; + return; + } + + char *name = construct_name(stage, source, dump_path); + f = fopen(name, "w"); + if (f) { + fputs(source, f); + fclose(f); + } else { + GET_CURRENT_CONTEXT(ctx); + _mesa_warning(ctx, "could not open %s for dumping shader (%s)", name, + strerror(errno)); + } + ralloc_free(name); +} /** * Read shader source code from a file. * Useful for debugging to override an app's shader. */ static GLcharARB * -read_shader(const char *fname) +read_shader(const gl_shader_stage stage, const char *source) { - int shader_size = 0; - FILE *f = fopen(fname, "r"); - GLcharARB *buffer, *shader; - int len; + char *read_path; + static bool path_exists = true; + int len, shader_size = 0; + GLcharARB *buffer; + FILE *f; + + if (!path_exists) + return NULL; - if (!f) { + read_path = getenv("MESA_SHADER_READ_PATH"); + if (!read_path) { + path_exists = false; return NULL; } + char *name = construct_name(stage, source, read_path); + f = fopen(name, "r"); + ralloc_free(name); + if (!f) + return NULL; + /* allocate enough room for the entire shader */ fseek(f, 0, SEEK_END); shader_size = ftell(f); @@ -1449,12 +1744,10 @@ read_shader(const char *fname) fclose(f); - shader = strdup(buffer); - free(buffer); - - return shader; + return buffer; } +#endif /* ENABLE_SHADER_CACHE */ /** * Called via glShaderSource() and glShaderSourceARB() API functions. @@ -1462,16 +1755,20 @@ read_shader(const char *fname) * and pass it to _mesa_shader_source(). */ void GLAPIENTRY -_mesa_ShaderSource(GLhandleARB shaderObj, GLsizei count, - const GLcharARB * const * string, const GLint * length) +_mesa_ShaderSource(GLuint shaderObj, GLsizei count, + const GLchar * const * string, const GLint * length) { GET_CURRENT_CONTEXT(ctx); GLint *offsets; GLsizei i, totalLength; GLcharARB *source; - GLuint checksum; + struct gl_shader *sh; - if (!shaderObj || string == NULL) { + sh = _mesa_lookup_shader_err(ctx, shaderObj, "glShaderSourceARB"); + if (!sh) + return; + + if (string == NULL) { _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSourceARB"); return; } @@ -1522,70 +1819,65 @@ _mesa_ShaderSource(GLhandleARB shaderObj, GLsizei count, source[totalLength - 1] = '\0'; source[totalLength - 2] = '\0'; - if (SHADER_SUBST) { - /* Compute the shader's source code checksum then try to open a file - * named newshader_. If it exists, use it in place of the - * original shader source code. For debugging. - */ - char filename[100]; - GLcharARB *newSource; - - checksum = _mesa_str_checksum(source); +#ifdef ENABLE_SHADER_CACHE + GLcharARB *replacement; - _mesa_snprintf(filename, sizeof(filename), "newshader_%d", checksum); + /* 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); - newSource = read_shader(filename); - if (newSource) { - fprintf(stderr, "Mesa: Replacing shader %u chksum=%d with %s\n", - shaderObj, checksum, filename); - free(source); - source = newSource; - } + replacement = read_shader(sh->Stage, source); + if (replacement) { + free(source); + source = replacement; } +#endif /* ENABLE_SHADER_CACHE */ - shader_source(ctx, shaderObj, source); - - if (SHADER_SUBST) { - struct gl_shader *sh = _mesa_lookup_shader(ctx, shaderObj); - if (sh) - sh->SourceChecksum = checksum; /* save original checksum */ - } + shader_source(sh, source); free(offsets); } -void GLAPIENTRY -_mesa_UseProgram(GLhandleARB program) +static ALWAYS_INLINE void +use_program(GLuint program, bool no_error) { GET_CURRENT_CONTEXT(ctx); - struct gl_shader_program *shProg; + struct gl_shader_program *shProg = NULL; - if (_mesa_is_xfb_active_and_unpaused(ctx)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glUseProgram(transform feedback active)"); - return; - } + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glUseProgram %u\n", program); - 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->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); + } } } - else { - shProg = NULL; - } /* The ARB_separate_shader_object spec says: * @@ -1596,26 +1888,44 @@ _mesa_UseProgram(GLhandleARB 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 */ - _mesa_use_program(ctx, shProg); + _mesa_use_shader_program(ctx, shProg); } else { /* Must be done first: detach the progam */ - _mesa_use_program(ctx, shProg); + _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); } } } void GLAPIENTRY -_mesa_ValidateProgram(GLhandleARB program) +_mesa_UseProgram_no_error(GLuint program) +{ + use_program(program, true); +} + + +void GLAPIENTRY +_mesa_UseProgram(GLuint program) +{ + use_program(program, false); +} + + +void GLAPIENTRY +_mesa_ValidateProgram(GLuint program) { GET_CURRENT_CONTEXT(ctx); validate_program(ctx, program); @@ -1695,12 +2005,23 @@ _mesa_ShaderBinary(GLint n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLint length) { GET_CURRENT_CONTEXT(ctx); - (void) n; (void) shaders; (void) binaryformat; (void) binary; - (void) length; - _mesa_error(ctx, GL_INVALID_OPERATION, "glShaderBinary"); + + /* 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: + * + * "An INVALID_VALUE error is generated if count or length is negative. + * An INVALID_ENUM error is generated if binaryformat is not a supported + * format returned in SHADER_BINARY_FORMATS." + */ + if (n < 0 || length < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glShaderBinary(count or length < 0)"); + return; + } + + _mesa_error(ctx, GL_INVALID_ENUM, "glShaderBinary(format)"); } @@ -1738,7 +2059,7 @@ _mesa_GetProgramBinary(GLuint program, GLsizei bufSize, GLsizei *length, * length is zero, and a call to GetProgramBinary will generate an * INVALID_OPERATION error. */ - if (!shProg->LinkStatus) { + if (!shProg->data->LinkStatus) { _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramBinary(program %u not linked)", shProg->Name); @@ -1790,7 +2111,7 @@ _mesa_ProgramBinary(GLuint program, GLenum binaryFormat, * Since any value of binaryFormat passed "is not one of those specified as * allowable for [this] command, an INVALID_ENUM error is generated." */ - shProg->LinkStatus = GL_FALSE; + shProg->data->LinkStatus = linking_failure; _mesa_error(ctx, GL_INVALID_ENUM, "glProgramBinary"); } @@ -1860,7 +2181,7 @@ _mesa_ProgramParameteri(GLuint program, GLenum pname, GLint value) default: _mesa_error(ctx, GL_INVALID_ENUM, "glProgramParameteri(pname=%s)", - _mesa_lookup_enum_by_nr(pname)); + _mesa_enum_to_string(pname)); return; } @@ -1868,63 +2189,128 @@ invalid_value: _mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameteri(pname=%s, value=%d): " "value must be 0 or 1.", - _mesa_lookup_enum_by_nr(pname), + _mesa_enum_to_string(pname), value); } void -_mesa_use_shader_program(struct gl_context *ctx, GLenum type, - struct gl_shader_program *shProg, - struct gl_pipeline_object *shTarget) +_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) { - gl_shader_stage stage = _mesa_shader_enum_to_shader_stage(type); - use_shader_program(ctx, stage, shProg, shTarget); + struct gl_program **target; - if (ctx->Driver.UseProgram) - ctx->Driver.UseProgram(ctx, shProg); -} + 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); + } -static GLuint -_mesa_create_shader_program(struct gl_context* ctx, GLboolean separate, - GLenum type, GLsizei count, const GLchar* const *strings) + _mesa_reference_shader_program(ctx, + &shTarget->ReferencedPrograms[stage], + shProg); + _mesa_reference_program(ctx, target, prog); + return; + } + +} + + +/** + * Copy program-specific data generated by linking from the gl_shader_program + * object to the gl_program object referred to by the gl_linked_shader. + * + * This function expects _mesa_reference_program() to have been previously + * called setting the gl_linked_shaders program reference. + */ +void +_mesa_copy_linked_program_data(const struct gl_shader_program *src, + struct gl_linked_shader *dst_sh) { + assert(dst_sh->Program); + + struct gl_program *dst = dst_sh->Program; + + dst->info.separate_shader = src->SeparateShader; + + switch (dst_sh->Stage) { + case MESA_SHADER_GEOMETRY: { + dst->info.gs.vertices_in = src->Geom.VerticesIn; + dst->info.gs.uses_end_primitive = src->Geom.UsesEndPrimitive; + dst->info.gs.uses_streams = src->Geom.UsesStreams; + break; + } + case MESA_SHADER_FRAGMENT: { + dst->info.fs.depth_layout = src->FragDepthLayout; + break; + } + case MESA_SHADER_COMPUTE: { + dst->info.cs.shared_size = src->Comp.SharedSize; + break; + } + default: + break; + } +} + +/** + * ARB_separate_shader_objects: Compile & Link Program + */ +GLuint GLAPIENTRY +_mesa_CreateShaderProgramv(GLenum type, GLsizei count, + const GLchar* const *strings) +{ + GET_CURRENT_CONTEXT(ctx); + const GLuint shader = create_shader(ctx, type); GLuint program = 0; + /* + * According to OpenGL 4.5 and OpenGL ES 3.1 standards, section 7.3: + * GL_INVALID_VALUE should be generated if count < 0 + */ + if (count < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "glCreateShaderProgram (count < 0)"); + return program; + } + if (shader) { - _mesa_ShaderSource(shader, count, strings, NULL); + struct gl_shader *sh = _mesa_lookup_shader(ctx, shader); - compile_shader(ctx, shader); + _mesa_ShaderSource(shader, count, strings, NULL); + _mesa_compile_shader(ctx, sh); program = create_shader_program(ctx); if (program) { struct gl_shader_program *shProg; - struct gl_shader *sh; GLint compiled = GL_FALSE; shProg = _mesa_lookup_shader_program(ctx, program); - sh = _mesa_lookup_shader(ctx, shader); - shProg->SeparateShader = separate; + shProg->SeparateShader = GL_TRUE; get_shaderiv(ctx, shader, GL_COMPILE_STATUS, &compiled); if (compiled) { - attach_shader(ctx, program, shader); - link_program(ctx, program); + attach_shader_err(ctx, program, shader, "glCreateShaderProgramv"); + _mesa_link_program(ctx, shProg); detach_shader(ctx, program, shader); #if 0 /* Possibly... */ if (active-user-defined-varyings-in-linked-program) { append-error-to-info-log; - shProg->LinkStatus = GL_FALSE; + shProg->data->LinkStatus = linking_failure; } #endif } - - ralloc_strcat(&shProg->InfoLog, sh->InfoLog); + if (sh->InfoLog) + ralloc_strcat(&shProg->data->InfoLog, sh->InfoLog); } delete_shader(ctx, shader); @@ -1935,55 +2321,558 @@ _mesa_create_shader_program(struct gl_context* ctx, GLboolean separate, /** - * Copy program-specific data generated by linking from the gl_shader_program - * object to a specific gl_program object. + * For GL_ARB_tessellation_shader */ -void -_mesa_copy_linked_program_data(gl_shader_stage type, - const struct gl_shader_program *src, - struct gl_program *dst) +extern void GLAPIENTRY +_mesa_PatchParameteri(GLenum pname, GLint value) { - switch (type) { - case MESA_SHADER_VERTEX: - dst->UsesClipDistanceOut = src->Vert.UsesClipDistance; + 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_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_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) { + 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_linked_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_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; + } + + struct gl_program *p = shProg->_LinkedShaders[stage]->Program; + if (index >= p->sh.NumSubroutineUniforms) { + _mesa_error(ctx, GL_INVALID_VALUE, "%s: invalid index greater than GL_ACTIVE_SUBROUTINE_UNIFORMS", 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; + } break; - case MESA_SHADER_GEOMETRY: { - struct gl_geometry_program *dst_gp = (struct gl_geometry_program *) dst; - dst_gp->VerticesIn = src->Geom.VerticesIn; - dst_gp->VerticesOut = src->Geom.VerticesOut; - dst_gp->Invocations = src->Geom.Invocations; - dst_gp->InputType = src->Geom.InputType; - dst_gp->OutputType = src->Geom.OutputType; - dst->UsesClipDistanceOut = src->Geom.UsesClipDistance; - dst_gp->UsesEndPrimitive = src->Geom.UsesEndPrimitive; - dst_gp->UsesStreams = src->Geom.UsesStreams; } + case GL_COMPATIBLE_SUBROUTINES: { + res = _mesa_program_resource_find_index(shProg, resource_type, index); + if (res) { + uni = res->Data; + count = 0; + for (i = 0; i < p->sh.NumSubroutineFunctions; i++) { + struct gl_subroutine_function *fn = &p->sh.SubroutineFunctions[i]; + for (j = 0; j < fn->num_compat_types; j++) { + if (fn->types[j] == uni->type) { + values[count++] = i; + break; + } + } + } + } break; - case MESA_SHADER_FRAGMENT: { - struct gl_fragment_program *dst_fp = (struct gl_fragment_program *) dst; - dst_fp->FragDepthLayout = src->FragDepthLayout; } + case GL_UNIFORM_SIZE: + res = _mesa_program_resource_find_index(shProg, resource_type, index); + if (res) { + uni = res->Data; + values[0] = uni->array_elements ? uni->array_elements : 1; + } break; - case MESA_SHADER_COMPUTE: { - struct gl_compute_program *dst_cp = (struct gl_compute_program *) dst; - int i; - for (i = 0; i < 3; i++) - dst_cp->LocalSize[i] = src->Comp.LocalSize[i]; + case GL_UNIFORM_NAME_LENGTH: + res = _mesa_program_resource_find_index(shProg, resource_type, index); + if (res) { + values[0] = strlen(_mesa_program_resource_name(res)) + 1 + + ((_mesa_program_resource_array_size(res) != 0) ? 3 : 0); + } + break; + default: + _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name); + return; } +} + + +GLvoid GLAPIENTRY +_mesa_GetActiveSubroutineUniformName(GLuint program, GLenum shadertype, + GLuint index, GLsizei bufsize, + GLsizei *length, GLchar *name) +{ + GET_CURRENT_CONTEXT(ctx); + const char *api_name = "glGetActiveSubroutineUniformName"; + struct gl_shader_program *shProg; + GLenum resource_type; + gl_shader_stage stage; + + 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); + if (!shProg->_LinkedShaders[stage]) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name); + return; + } + + resource_type = _mesa_shader_stage_to_subroutine_uniform(stage); + /* get program resource name */ + _mesa_get_program_resource_name(shProg, resource_type, + index, bufsize, + length, name, api_name); +} + + +GLvoid GLAPIENTRY +_mesa_GetActiveSubroutineName(GLuint program, GLenum shadertype, + GLuint index, GLsizei bufsize, + GLsizei *length, GLchar *name) +{ + GET_CURRENT_CONTEXT(ctx); + const char *api_name = "glGetActiveSubroutineName"; + struct gl_shader_program *shProg; + GLenum resource_type; + gl_shader_stage stage; + + 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); + if (!shProg->_LinkedShaders[stage]) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name); + return; + } + resource_type = _mesa_shader_stage_to_subroutine(stage); + _mesa_get_program_resource_name(shProg, resource_type, + index, bufsize, + length, name, api_name); +} + +GLvoid GLAPIENTRY +_mesa_UniformSubroutinesuiv(GLenum shadertype, GLsizei count, + const GLuint *indices) +{ + GET_CURRENT_CONTEXT(ctx); + const char *api_name = "glUniformSubroutinesuiv"; + gl_shader_stage stage; + int i; + + if (!_mesa_validate_shader_target(ctx, shadertype)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name); + return; + } + + stage = _mesa_shader_enum_to_shader_stage(shadertype); + struct gl_program *p = ctx->_Shader->CurrentProgram[stage]; + if (!p) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name); + return; + } + + if (count != p->sh.NumSubroutineUniformRemapTable) { + _mesa_error(ctx, GL_INVALID_VALUE, "%s", api_name); + return; + } + + i = 0; + bool flushed = false; + do { + struct gl_uniform_storage *uni = p->sh.SubroutineUniformRemapTable[i]; + if (uni == NULL) { + i++; + 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; + + for (j = i; j < i + uni_count; j++) { + struct gl_subroutine_function *subfn = NULL; + if (indices[j] > p->sh.MaxSubroutineFunctionIndex) { + _mesa_error(ctx, GL_INVALID_VALUE, "%s", api_name); + return; + } + + for (f = 0; f < p->sh.NumSubroutineFunctions; f++) { + if (p->sh.SubroutineFunctions[f].index == indices[j]) + subfn = &p->sh.SubroutineFunctions[f]; + } + + if (!subfn) { + continue; + } + + for (k = 0; k < subfn->num_compat_types; k++) { + if (subfn->types[k] == uni->type) + break; + } + if (k == subfn->num_compat_types) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name); + return; + } + + ctx->SubroutineIndex[p->info.stage].IndexPtr[j] = indices[j]; + } + i += uni_count; + } while(i < count); +} + + +GLvoid GLAPIENTRY +_mesa_GetUniformSubroutineuiv(GLenum shadertype, GLint location, + GLuint *params) +{ + GET_CURRENT_CONTEXT(ctx); + const char *api_name = "glGetUniformSubroutineuiv"; + gl_shader_stage stage; + + if (!_mesa_validate_shader_target(ctx, shadertype)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name); + return; + } + + stage = _mesa_shader_enum_to_shader_stage(shadertype); + struct gl_program *p = ctx->_Shader->CurrentProgram[stage]; + if (!p) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name); + return; + } + + if (location >= p->sh.NumSubroutineUniformRemapTable) { + _mesa_error(ctx, GL_INVALID_VALUE, "%s", api_name); + return; + } + + *params = ctx->SubroutineIndex[p->info.stage].IndexPtr[location]; +} + + +GLvoid GLAPIENTRY +_mesa_GetProgramStageiv(GLuint program, GLenum shadertype, + GLenum pname, GLint *values) +{ + 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_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]; + + /* ARB_shader_subroutine doesn't ask the program to be linked, or list any + * INVALID_OPERATION in the case of not be linked. + * + * And for some pnames, like GL_ACTIVE_SUBROUTINE_UNIFORMS, you can ask the + * same info using other specs (ARB_program_interface_query), without the + * need of the program to be linked, being the value for that case 0. + * + * But at the same time, some other methods require the program to be + * linked for pname related to locations, so it would be inconsistent to + * not do the same here. So we are: + * * Return GL_INVALID_OPERATION if not linked only for locations. + * * Setting a default value of 0, to be returned if not linked. + */ + if (!sh) { + values[0] = 0; + if (pname == GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s", api_name); + } + return; + } + + struct gl_program *p = sh->Program; + switch (pname) { + case GL_ACTIVE_SUBROUTINES: + values[0] = p->sh.NumSubroutineFunctions; + break; + case GL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS: + values[0] = p->sh.NumSubroutineUniformRemapTable; + break; + case GL_ACTIVE_SUBROUTINE_UNIFORMS: + values[0] = p->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 < p->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 < p->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; } } -/** - * ARB_separate_shader_objects: Compile & Link Program - */ -GLuint GLAPIENTRY -_mesa_CreateShaderProgramv(GLenum type, GLsizei count, - const GLchar* const *strings) +static int +find_compat_subroutine(struct gl_program *p, const struct glsl_type *type) { - GET_CURRENT_CONTEXT(ctx); + int i, j; + + for (i = 0; i < p->sh.NumSubroutineFunctions; i++) { + struct gl_subroutine_function *fn = &p->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_write_subroutine_index(struct gl_context *ctx, + struct gl_program *p) +{ + int i, j; + + if (p->sh.NumSubroutineUniformRemapTable == 0) + return; + + i = 0; + do { + struct gl_uniform_storage *uni = p->sh.SubroutineUniformRemapTable[i]; + int uni_count; + int val; - return _mesa_create_shader_program(ctx, GL_TRUE, type, count, strings); + if (!uni) { + i++; + continue; + } + + uni_count = uni->array_elements ? uni->array_elements : 1; + for (j = 0; j < uni_count; j++) { + val = ctx->SubroutineIndex[p->info.stage].IndexPtr[i + j]; + memcpy(&uni->storage[j], &val, sizeof(int)); + } + + _mesa_propagate_uniforms_to_driver_storage(uni, 0, uni_count); + i += uni_count; + } while(i < p->sh.NumSubroutineUniformRemapTable); +} + +void +_mesa_shader_write_subroutine_indices(struct gl_context *ctx, + gl_shader_stage stage) +{ + if (ctx->_Shader->CurrentProgram[stage]) + _mesa_shader_write_subroutine_index(ctx, + ctx->_Shader->CurrentProgram[stage]); +} + +void +_mesa_program_init_subroutine_defaults(struct gl_context *ctx, + struct gl_program *p) +{ + assert(p); + + struct gl_subroutine_index_binding *binding = &ctx->SubroutineIndex[p->info.stage]; + if (binding->NumIndex != p->sh.NumSubroutineUniformRemapTable) { + binding->IndexPtr = realloc(binding->IndexPtr, + p->sh.NumSubroutineUniformRemapTable * (sizeof(GLuint))); + binding->NumIndex = p->sh.NumSubroutineUniformRemapTable; + } + + for (int i = 0; i < p->sh.NumSubroutineUniformRemapTable; i++) { + struct gl_uniform_storage *uni = p->sh.SubroutineUniformRemapTable[i]; + + if (!uni) + continue; + + binding->IndexPtr[i] = find_compat_subroutine(p, uni->type); + } }