diff options
Diffstat (limited to 'src/mesa/main/shaderapi.c')
-rw-r--r-- | src/mesa/main/shaderapi.c | 315 |
1 files changed, 260 insertions, 55 deletions
diff --git a/src/mesa/main/shaderapi.c b/src/mesa/main/shaderapi.c index c25d2a19747..e6c7f7aa3f8 100644 --- a/src/mesa/main/shaderapi.c +++ b/src/mesa/main/shaderapi.c @@ -47,7 +47,7 @@ #include "program/prog_parameter.h" #include "program/prog_uniform.h" #include "talloc.h" - +#include <stdbool.h> /** Define this to enable shader substitution (see below) */ #define SHADER_SUBST 0 @@ -89,7 +89,7 @@ get_shader_flags(void) * Initialize context's shader state. */ void -_mesa_init_shader_state(GLcontext *ctx) +_mesa_init_shader_state(struct gl_context *ctx) { /* Device drivers may override these to control what kind of instructions * are generated by the GLSL compiler. @@ -114,9 +114,14 @@ _mesa_init_shader_state(GLcontext *ctx) * Free the per-context shader-related state. */ void -_mesa_free_shader_state(GLcontext *ctx) +_mesa_free_shader_state(struct gl_context *ctx) { - _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, NULL); + _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentVertexProgram, NULL); + _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentGeometryProgram, + NULL); + _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentFragmentProgram, + NULL); + _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, NULL); } @@ -202,6 +207,35 @@ _mesa_copy_string(GLchar *dst, GLsizei maxLength, /** + * Confirm that the a shader type is valid and supported by the implementation + * + * \param ctx Current GL context + * \param type Shader target + * + */ +static bool +validate_shader_target(const struct gl_context *ctx, GLenum type) +{ + switch (type) { +#if FEATURE_ARB_fragment_shader + case GL_FRAGMENT_SHADER: + return ctx->Extensions.ARB_fragment_shader; +#endif +#if FEATURE_ARB_vertex_shader + case GL_VERTEX_SHADER: + return ctx->Extensions.ARB_vertex_shader; +#endif +#if FEATURE_ARB_geometry_shader4 + case GL_GEOMETRY_SHADER_ARB: + return ctx->Extensions.ARB_geometry_shader4; +#endif + default: + return false; + } +} + + +/** * Find the length of the longest transform feedback varying name * which was specified with glTransformFeedbackVaryings(). */ @@ -221,7 +255,7 @@ longest_feedback_varying_name(const struct gl_shader_program *shProg) static GLboolean -is_program(GLcontext *ctx, GLuint name) +is_program(struct gl_context *ctx, GLuint name) { struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name); return shProg ? GL_TRUE : GL_FALSE; @@ -229,7 +263,7 @@ is_program(GLcontext *ctx, GLuint name) static GLboolean -is_shader(GLcontext *ctx, GLuint name) +is_shader(struct gl_context *ctx, GLuint name) { struct gl_shader *shader = _mesa_lookup_shader(ctx, name); return shader ? GL_TRUE : GL_FALSE; @@ -240,7 +274,7 @@ is_shader(GLcontext *ctx, GLuint name) * Attach shader to a shader program. */ static void -attach_shader(GLcontext *ctx, GLuint program, GLuint shader) +attach_shader(struct gl_context *ctx, GLuint program, GLuint shader) { struct gl_shader_program *shProg; struct gl_shader *sh; @@ -287,7 +321,7 @@ attach_shader(GLcontext *ctx, GLuint program, GLuint shader) static GLint -get_attrib_location(GLcontext *ctx, GLuint program, const GLchar *name) +get_attrib_location(struct gl_context *ctx, GLuint program, const GLchar *name) { struct gl_shader_program *shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation"); @@ -320,7 +354,7 @@ get_attrib_location(GLcontext *ctx, GLuint program, const GLchar *name) static void -bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index, +bind_attrib_location(struct gl_context *ctx, GLuint program, GLuint index, const GLchar *name) { struct gl_shader_program *shProg; @@ -371,24 +405,18 @@ bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index, static GLuint -create_shader(GLcontext *ctx, GLenum type) +create_shader(struct gl_context *ctx, GLenum type) { struct gl_shader *sh; GLuint name; - name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1); - - switch (type) { - case GL_FRAGMENT_SHADER: - case GL_VERTEX_SHADER: - case GL_GEOMETRY_SHADER_ARB: - sh = ctx->Driver.NewShader(ctx, name, type); - break; - default: + if (!validate_shader_target(ctx, type)) { _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)"); return 0; } + name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1); + sh = ctx->Driver.NewShader(ctx, name, type); _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh); return name; @@ -396,7 +424,7 @@ create_shader(GLcontext *ctx, GLenum type) static GLuint -create_shader_program(GLcontext *ctx) +create_shader_program(struct gl_context *ctx) { GLuint name; struct gl_shader_program *shProg; @@ -418,7 +446,7 @@ create_shader_program(GLcontext *ctx) * DeleteProgramARB. */ static void -delete_shader_program(GLcontext *ctx, GLuint name) +delete_shader_program(struct gl_context *ctx, GLuint name) { /* * NOTE: deleting shaders/programs works a bit differently than @@ -442,7 +470,7 @@ delete_shader_program(GLcontext *ctx, GLuint name) static void -delete_shader(GLcontext *ctx, GLuint shader) +delete_shader(struct gl_context *ctx, GLuint shader) { struct gl_shader *sh; @@ -458,7 +486,7 @@ delete_shader(GLcontext *ctx, GLuint shader) static void -detach_shader(GLcontext *ctx, GLuint program, GLuint shader) +detach_shader(struct gl_context *ctx, GLuint program, GLuint shader) { struct gl_shader_program *shProg; GLuint n; @@ -526,7 +554,7 @@ detach_shader(GLcontext *ctx, GLuint program, GLuint shader) static void -get_active_attrib(GLcontext *ctx, GLuint program, GLuint index, +get_active_attrib(struct gl_context *ctx, GLuint program, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLchar *nameOut) { @@ -561,7 +589,7 @@ get_active_attrib(GLcontext *ctx, GLuint program, GLuint index, * Return list of shaders attached to shader program. */ static void -get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount, +get_attached_shaders(struct gl_context *ctx, GLuint program, GLsizei maxCount, GLsizei *count, GLuint *obj) { struct gl_shader_program *shProg = @@ -581,11 +609,11 @@ get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount, * glGetHandleARB() - return ID/name of currently bound shader program. */ static GLuint -get_handle(GLcontext *ctx, GLenum pname) +get_handle(struct gl_context *ctx, GLenum pname) { if (pname == GL_PROGRAM_OBJECT_ARB) { - if (ctx->Shader.CurrentProgram) - return ctx->Shader.CurrentProgram->Name; + if (ctx->Shader.ActiveProgram) + return ctx->Shader.ActiveProgram->Name; else return 0; } @@ -602,7 +630,7 @@ get_handle(GLcontext *ctx, GLenum pname) * programs (see glGetProgramivARB). */ static void -get_programiv(GLcontext *ctx, GLuint program, GLenum pname, GLint *params) +get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, GLint *params) { const struct gl_program_parameter_list *attribs; struct gl_shader_program *shProg @@ -684,7 +712,7 @@ get_programiv(GLcontext *ctx, GLuint program, GLenum pname, GLint *params) * glGetShaderiv() - get GLSL shader state */ static void -get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params) +get_shaderiv(struct gl_context *ctx, GLuint name, GLenum pname, GLint *params) { struct gl_shader *shader = _mesa_lookup_shader_err(ctx, name, "glGetShaderiv"); @@ -717,7 +745,7 @@ get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params) static void -get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize, +get_program_info_log(struct gl_context *ctx, GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) { struct gl_shader_program *shProg @@ -731,7 +759,7 @@ get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize, static void -get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize, +get_shader_info_log(struct gl_context *ctx, GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) { struct gl_shader *sh = _mesa_lookup_shader(ctx, shader); @@ -747,7 +775,7 @@ get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize, * Return shader source code. */ static void -get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength, +get_shader_source(struct gl_context *ctx, GLuint shader, GLsizei maxLength, GLsizei *length, GLchar *sourceOut) { struct gl_shader *sh; @@ -763,7 +791,7 @@ get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength, * Set/replace shader source code. */ static void -shader_source(GLcontext *ctx, GLuint shader, const GLchar *source) +shader_source(struct gl_context *ctx, GLuint shader, const GLchar *source) { struct gl_shader *sh; @@ -787,7 +815,7 @@ shader_source(GLcontext *ctx, GLuint shader, const GLchar *source) * Compile a shader. */ static void -compile_shader(GLcontext *ctx, GLuint shaderObj) +compile_shader(struct gl_context *ctx, GLuint shaderObj) { struct gl_shader *sh; struct gl_shader_compiler_options *options; @@ -812,7 +840,7 @@ compile_shader(GLcontext *ctx, GLuint shaderObj) * Link a program's shaders. */ static void -link_program(GLcontext *ctx, GLuint program) +link_program(struct gl_context *ctx, GLuint program) { struct gl_shader_program *shProg; struct gl_transform_feedback_object *obj = @@ -822,7 +850,10 @@ link_program(GLcontext *ctx, GLuint program) if (!shProg) return; - if (obj->Active && shProg == ctx->Shader.CurrentProgram) { + if (obj->Active + && (shProg == ctx->Shader.CurrentVertexProgram + || shProg == ctx->Shader.CurrentGeometryProgram + || shProg == ctx->Shader.CurrentFragmentProgram)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glLinkProgram(transform feedback active"); return; @@ -885,14 +916,81 @@ print_shader_info(const struct gl_shader_program *shProg) /** + * Use the named shader program for subsequent glUniform calls + */ +static void +active_program(struct gl_context *ctx, struct gl_shader_program *shProg, + const char *caller) +{ + if ((shProg != NULL) && !shProg->LinkStatus) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(program %u not linked)", caller, shProg->Name); + return; + } + + if (ctx->Shader.ActiveProgram != shProg) { + _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram, shProg); + } +} + +/** + */ +static bool +use_shader_program(struct gl_context *ctx, GLenum type, + struct gl_shader_program *shProg) +{ + struct gl_shader_program **target; + + switch (type) { +#if FEATURE_ARB_vertex_shader + case GL_VERTEX_SHADER: + target = &ctx->Shader.CurrentVertexProgram; + if ((shProg == NULL) + || (shProg->_LinkedShaders[MESA_SHADER_VERTEX] == NULL)) { + shProg = NULL; + } + break; +#endif +#if FEATURE_ARB_geometry_shader4 + case GL_GEOMETRY_SHADER_ARB: + target = &ctx->Shader.CurrentGeometryProgram; + if ((shProg == NULL) + || (shProg->_LinkedShaders[MESA_SHADER_GEOMETRY] == NULL)) { + shProg = NULL; + } + break; +#endif +#if FEATURE_ARB_fragment_shader + case GL_FRAGMENT_SHADER: + target = &ctx->Shader.CurrentFragmentProgram; + if ((shProg == NULL) + || (shProg->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL)) { + shProg = NULL; + } + break; +#endif + default: + return false; + } + + if (*target != shProg) { + _mesa_reference_shader_program(ctx, target, shProg); + return true; + } + + return false; +} + +/** * Use the named shader program for subsequent rendering. */ void -_mesa_use_program(GLcontext *ctx, GLuint program) +_mesa_use_program(struct gl_context *ctx, GLuint program) { struct gl_shader_program *shProg; struct gl_transform_feedback_object *obj = ctx->TransformFeedback.CurrentObject; + bool changed = false; if (obj->Active) { _mesa_error(ctx, GL_INVALID_OPERATION, @@ -900,12 +998,6 @@ _mesa_use_program(GLcontext *ctx, GLuint program) return; } - if (ctx->Shader.CurrentProgram && - ctx->Shader.CurrentProgram->Name == program) { - /* no-op */ - return; - } - if (program) { shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram"); if (!shProg) { @@ -926,9 +1018,15 @@ _mesa_use_program(GLcontext *ctx, GLuint program) shProg = NULL; } - if (ctx->Shader.CurrentProgram != shProg) { + changed = use_shader_program(ctx, GL_VERTEX_SHADER, shProg); + changed = use_shader_program(ctx, GL_GEOMETRY_SHADER_ARB, shProg) + || changed; + changed = use_shader_program(ctx, GL_FRAGMENT_SHADER, shProg) + || changed; + active_program(ctx, shProg, "glUseProgram"); + + if (changed) { FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS); - _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg); } if (ctx->Driver.UseProgram) @@ -943,7 +1041,7 @@ _mesa_use_program(GLcontext *ctx, GLuint program) * \return GL_TRUE if valid, GL_FALSE if invalid */ static GLboolean -validate_samplers(GLcontext *ctx, const struct gl_program *prog, char *errMsg) +validate_samplers(const struct gl_program *prog, char *errMsg) { static const char *targetName[] = { "TEXTURE_2D_ARRAY", @@ -975,7 +1073,7 @@ validate_samplers(GLcontext *ctx, const struct gl_program *prog, char *errMsg) assert(sampler < MAX_TEXTURE_IMAGE_UNITS); unit = prog->SamplerUnits[sampler]; target = prog->SamplerTargets[sampler]; - if (targetUsed[unit] != -1 && targetUsed[unit] != target) { + if (targetUsed[unit] != -1 && targetUsed[unit] != (int) target) { _mesa_snprintf(errMsg, 100, "Texture unit %d is accessed both as %s and %s", unit, targetName[targetUsed[unit]], targetName[target]); @@ -995,8 +1093,7 @@ validate_samplers(GLcontext *ctx, const struct gl_program *prog, char *errMsg) * \return GL_TRUE if valid, GL_FALSE if invalid (and set errMsg) */ static GLboolean -validate_shader_program(GLcontext *ctx, - const struct gl_shader_program *shProg, +validate_shader_program(const struct gl_shader_program *shProg, char *errMsg) { const struct gl_vertex_program *vp = shProg->VertexProgram; @@ -1026,10 +1123,10 @@ validate_shader_program(GLcontext *ctx, * Check: any two active samplers in the current program object are of * different types, but refer to the same texture image unit, */ - if (vp && !validate_samplers(ctx, &vp->Base, errMsg)) { + if (vp && !validate_samplers(&vp->Base, errMsg)) { return GL_FALSE; } - if (fp && !validate_samplers(ctx, &fp->Base, errMsg)) { + if (fp && !validate_samplers(&fp->Base, errMsg)) { return GL_FALSE; } @@ -1041,7 +1138,7 @@ validate_shader_program(GLcontext *ctx, * Called via glValidateProgram() */ static void -validate_program(GLcontext *ctx, GLuint program) +validate_program(struct gl_context *ctx, GLuint program) { struct gl_shader_program *shProg; char errMsg[100]; @@ -1051,7 +1148,7 @@ validate_program(GLcontext *ctx, GLuint program) return; } - shProg->Validated = validate_shader_program(ctx, shProg, errMsg); + shProg->Validated = validate_shader_program(shProg, errMsg); if (!shProg->Validated) { /* update info log */ if (shProg->InfoLog) { @@ -1498,6 +1595,10 @@ _mesa_GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) { GET_CURRENT_CONTEXT(ctx); + (void) shadertype; + (void) precisiontype; + (void) range; + (void) precision; _mesa_error(ctx, GL_INVALID_OPERATION, __FUNCTION__); } @@ -1515,6 +1616,11 @@ _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, __FUNCTION__); } @@ -1540,7 +1646,7 @@ _mesa_ProgramParameteriARB(GLuint program, GLenum pname, switch (pname) { case GL_GEOMETRY_VERTICES_OUT_ARB: if (value < 1 || - value > ctx->Const.GeometryProgram.MaxGeometryOutputVertices) { + (unsigned) value > ctx->Const.GeometryProgram.MaxGeometryOutputVertices) { _mesa_error(ctx, GL_INVALID_VALUE, "glProgramParameteri(GL_GEOMETRY_VERTICES_OUT_ARB=%d", value); @@ -1587,6 +1693,101 @@ _mesa_ProgramParameteriARB(GLuint program, GLenum pname, #endif +void GLAPIENTRY +_mesa_UseShaderProgramEXT(GLenum type, GLuint program) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_shader_program *shProg = NULL; + bool changed = false; + + if (!validate_shader_target(ctx, type)) { + _mesa_error(ctx, GL_INVALID_ENUM, "glUseShaderProgramEXT(type)"); + return; + } + + if (ctx->TransformFeedback.CurrentObject->Active) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glUseShaderProgramEXT(transform feedback is active)"); + return; + } + + if (program) { + shProg = _mesa_lookup_shader_program_err(ctx, program, + "glUseShaderProgramEXT"); + if (shProg == NULL) + return; + + if (!shProg->LinkStatus) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glUseShaderProgramEXT(program not linked)"); + return; + } + } + + changed = use_shader_program(ctx, type, shProg); + if (changed) + FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS); + + if (ctx->Driver.UseProgram) + ctx->Driver.UseProgram(ctx, shProg); + return; +} + +void GLAPIENTRY +_mesa_ActiveProgramEXT(GLuint program) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_shader_program *shProg = (program != 0) + ? _mesa_lookup_shader_program_err(ctx, program, "glActiveProgramEXT") + : NULL; + + active_program(ctx, shProg, "glActiveProgramEXT"); + return; +} + +GLuint GLAPIENTRY +_mesa_CreateShaderProgramEXT(GLenum type, const GLchar *string) +{ + GET_CURRENT_CONTEXT(ctx); + const GLuint shader = create_shader(ctx, type); + GLuint program = 0; + + if (shader) { + shader_source(ctx, shader, _mesa_strdup(string)); + compile_shader(ctx, shader); + + 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); + + get_shaderiv(ctx, shader, GL_COMPILE_STATUS, &compiled); + if (compiled) { + attach_shader(ctx, program, shader); + link_program(ctx, program); + 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; + } +#endif + } + + shProg->InfoLog = talloc_strdup_append(shProg->InfoLog, sh->InfoLog); + } + + delete_shader(ctx, shader); + } + + return program; +} /** * Plug in shader-related functions into API dispatch table. @@ -1637,6 +1838,10 @@ _mesa_init_shader_dispatch(struct _glapi_table *exec) #if FEATURE_ARB_geometry_shader4 SET_ProgramParameteriARB(exec, _mesa_ProgramParameteriARB); #endif + + SET_UseShaderProgramEXT(exec, _mesa_UseShaderProgramEXT); + SET_ActiveProgramEXT(exec, _mesa_ActiveProgramEXT); + SET_CreateShaderProgramEXT(exec, _mesa_CreateShaderProgramEXT); #endif /* FEATURE_GL */ } |