diff options
Diffstat (limited to 'src/mesa/main')
-rw-r--r-- | src/mesa/main/context.c | 150 | ||||
-rw-r--r-- | src/mesa/main/mtypes.h | 10 | ||||
-rw-r--r-- | src/mesa/main/shaderapi.c | 89 | ||||
-rw-r--r-- | src/mesa/main/state.c | 16 | ||||
-rw-r--r-- | src/mesa/main/texenvprogram.c | 9 | ||||
-rw-r--r-- | src/mesa/main/texstate.c | 33 |
6 files changed, 218 insertions, 89 deletions
diff --git a/src/mesa/main/context.c b/src/mesa/main/context.c index 3e265fb3087..3ebe54926ff 100644 --- a/src/mesa/main/context.c +++ b/src/mesa/main/context.c @@ -1697,11 +1697,10 @@ _mesa_valid_to_render(struct gl_context *ctx, const char *where) if (ctx->NewState) _mesa_update_state(ctx); - if (ctx->Shader.CurrentProgram) { - struct gl_shader_program *const prog = ctx->Shader.CurrentProgram; + if (ctx->Shader.CurrentVertexProgram) { + vert_from_glsl_shader = true; - /* The current shader program must be successfully linked */ - if (!prog->LinkStatus) { + if (!ctx->Shader.CurrentVertexProgram->LinkStatus) { _mesa_error(ctx, GL_INVALID_OPERATION, "%s(shader not linked)", where); return GL_FALSE; @@ -1709,34 +1708,56 @@ _mesa_valid_to_render(struct gl_context *ctx, const char *where) #if 0 /* not normally enabled */ { char errMsg[100]; - if (!_mesa_validate_shader_program(ctx, prog, errMsg)) { + if (!_mesa_validate_shader_program(ctx, + ctx->Shader.CurrentVertexProgram, + errMsg)) { _mesa_warning(ctx, "Shader program %u is invalid: %s", - prog->Name, errMsg); + ctx->Shader.CurrentVertexProgram->Name, errMsg); } } #endif + } - /* Figure out which shader stages are provided by the GLSL program. For - * any stages that are not provided, the corresponding assembly shader - * target will be validated below. - */ - vert_from_glsl_shader = - prog->_LinkedShaders[MESA_SHADER_VERTEX] != NULL; - geom_from_glsl_shader = - prog->_LinkedShaders[MESA_SHADER_GEOMETRY] != NULL; - frag_from_glsl_shader = - prog->_LinkedShaders[MESA_SHADER_FRAGMENT] != NULL; + if (ctx->Shader.CurrentGeometryProgram) { + geom_from_glsl_shader = true; + + if (!ctx->Shader.CurrentGeometryProgram->LinkStatus) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(shader not linked)", where); + return GL_FALSE; + } +#if 0 /* not normally enabled */ + { + char errMsg[100]; + if (!_mesa_validate_shader_program(ctx, + ctx->Shader.CurrentGeometryProgram, + errMsg)) { + _mesa_warning(ctx, "Shader program %u is invalid: %s", + ctx->Shader.CurrentGeometryProgram->Name, errMsg); + } + } +#endif } - /* If drawing to integer-valued color buffers, there must be an - * active fragment shader (GL_EXT_texture_integer). - */ - if (ctx->DrawBuffer && ctx->DrawBuffer->_IntegerColor) { - if (!frag_from_glsl_shader) { + if (ctx->Shader.CurrentFragmentProgram) { + frag_from_glsl_shader = true; + + if (!ctx->Shader.CurrentFragmentProgram->LinkStatus) { _mesa_error(ctx, GL_INVALID_OPERATION, - "%s(integer format but no fragment shader)", where); + "%s(shader not linked)", where); return GL_FALSE; } +#if 0 /* not normally enabled */ + { + char errMsg[100]; + if (!_mesa_validate_shader_program(ctx, + ctx->Shader.CurrentFragmentProgram, + errMsg)) { + _mesa_warning(ctx, "Shader program %u is invalid: %s", + ctx->Shader.CurrentFragmentProgram->Name, errMsg); + } + } +#endif } /* Any shader stages that are not supplied by the GLSL shader and have @@ -1754,11 +1775,21 @@ _mesa_valid_to_render(struct gl_context *ctx, const char *where) */ (void) geom_from_glsl_shader; - if (!frag_from_glsl_shader - && ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "%s(fragment program not valid)", where); - return GL_FALSE; + if (!frag_from_glsl_shader) { + if (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(fragment program not valid)", where); + return GL_FALSE; + } + + /* If drawing to integer-valued color buffers, there must be an + * active fragment shader (GL_EXT_texture_integer). + */ + if (ctx->DrawBuffer && ctx->DrawBuffer->_IntegerColor) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(integer format but no fragment shader)", where); + return GL_FALSE; + } } if (ctx->DrawBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { @@ -1769,26 +1800,51 @@ _mesa_valid_to_render(struct gl_context *ctx, const char *where) #ifdef DEBUG if (ctx->Shader.Flags & GLSL_LOG) { - struct gl_shader_program *shProg = ctx->Shader.CurrentProgram; - if (shProg) { - if (!shProg->_Used) { - /* This is the first time this shader is being used. - * Append shader's constants/uniforms to log file. - */ - GLuint i; - for (i = 0; i < shProg->NumShaders; i++) { - struct gl_shader *sh = shProg->Shaders[i]; - if (sh->Type == GL_VERTEX_SHADER) { - _mesa_append_uniforms_to_file(sh, - &shProg->VertexProgram->Base); - } - else if (sh->Type == GL_FRAGMENT_SHADER) { - _mesa_append_uniforms_to_file(sh, - &shProg->FragmentProgram->Base); - } - } - shProg->_Used = GL_TRUE; - } + struct gl_shader_program *shProg[MESA_SHADER_TYPES]; + unsigned i; + + shProg[MESA_SHADER_VERTEX] = ctx->Shader.CurrentVertexProgram; + shProg[MESA_SHADER_GEOMETRY] = ctx->Shader.CurrentGeometryProgram; + shProg[MESA_SHADER_FRAGMENT] = ctx->Shader.CurrentFragmentProgram; + + for (i = 0; i < MESA_SHADER_TYPES; i++) { + struct gl_shader *sh; + + if (shProg[i] == NULL || shProg[i]->_Used + || shProg[i]->_LinkedShaders[i] == NULL) + continue; + + /* This is the first time this shader is being used. + * Append shader's constants/uniforms to log file. + * + * The logic is a little odd here. We only want to log data for each + * shader target that will actually be used, and we only want to log + * it once. It's possible to have a program bound to the vertex + * shader target that also supplied a fragment shader. If that + * program isn't also bound to the fragment shader target we don't + * want to log its fragment data. + */ + sh = shProg[i]->_LinkedShaders[i]; + switch (sh->Type) { + case GL_VERTEX_SHADER: + _mesa_append_uniforms_to_file(sh, &shProg[i]->VertexProgram->Base); + break; + + case GL_GEOMETRY_SHADER_ARB: + _mesa_append_uniforms_to_file(sh, + &shProg[i]->GeometryProgram->Base); + break; + + case GL_FRAGMENT_SHADER: + _mesa_append_uniforms_to_file(sh, + &shProg[i]->FragmentProgram->Base); + break; + } + } + + for (i = 0; i < MESA_SHADER_TYPES; i++) { + if (shProg[i] != NULL) + shProg[i]->_Used = GL_TRUE; } } #endif diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index 7863ef382de..1b8a80416c9 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -2142,9 +2142,15 @@ struct gl_shader_program struct gl_shader_state { /** - * Program used for rendering. + * Programs used for rendering + * + * There is a separate program set for each shader stage. If + * GL_EXT_separate_shader_objects is not supported, each of these must point + * to \c NULL or to the same program. */ - struct gl_shader_program *CurrentProgram; + struct gl_shader_program *CurrentVertexProgram; + struct gl_shader_program *CurrentGeometryProgram; + struct gl_shader_program *CurrentFragmentProgram; /** * Program used by glUniform calls. diff --git a/src/mesa/main/shaderapi.c b/src/mesa/main/shaderapi.c index 26c9a181aa0..e6c7f7aa3f8 100644 --- a/src/mesa/main/shaderapi.c +++ b/src/mesa/main/shaderapi.c @@ -116,7 +116,11 @@ _mesa_init_shader_state(struct gl_context *ctx) void _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); } @@ -846,7 +850,10 @@ link_program(struct gl_context *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; @@ -927,6 +934,54 @@ active_program(struct gl_context *ctx, struct gl_shader_program *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 @@ -935,6 +990,7 @@ _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, @@ -942,12 +998,6 @@ _mesa_use_program(struct gl_context *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) { @@ -959,8 +1009,6 @@ _mesa_use_program(struct gl_context *ctx, GLuint program) return; } - active_program(ctx, shProg, "glUseProgram"); - /* debug code */ if (ctx->Shader.Flags & GLSL_USE_PROG) { print_shader_info(shProg); @@ -970,9 +1018,15 @@ _mesa_use_program(struct gl_context *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) @@ -1643,7 +1697,8 @@ void GLAPIENTRY _mesa_UseShaderProgramEXT(GLenum type, GLuint program) { GET_CURRENT_CONTEXT(ctx); - struct gl_shader_program *shProg; + struct gl_shader_program *shProg = NULL; + bool changed = false; if (!validate_shader_target(ctx, type)) { _mesa_error(ctx, GL_INVALID_ENUM, "glUseShaderProgramEXT(type)"); @@ -1669,8 +1724,12 @@ _mesa_UseShaderProgramEXT(GLenum type, GLuint program) } } - _mesa_error(ctx, GL_INVALID_OPERATION, - "glUseShaderProgramEXT(NOT YET IMPLEMENTED)"); + 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; } diff --git a/src/mesa/main/state.c b/src/mesa/main/state.c index 5529732de07..05f4165c44a 100644 --- a/src/mesa/main/state.c +++ b/src/mesa/main/state.c @@ -247,7 +247,9 @@ update_program_enables(struct gl_context *ctx) static GLbitfield update_program(struct gl_context *ctx) { - const struct gl_shader_program *shProg = ctx->Shader.CurrentProgram; + const struct gl_shader_program *vsProg = ctx->Shader.CurrentVertexProgram; + const struct gl_shader_program *gsProg = ctx->Shader.CurrentGeometryProgram; + const struct gl_shader_program *fsProg = ctx->Shader.CurrentFragmentProgram; const struct gl_vertex_program *prevVP = ctx->VertexProgram._Current; const struct gl_fragment_program *prevFP = ctx->FragmentProgram._Current; const struct gl_geometry_program *prevGP = ctx->GeometryProgram._Current; @@ -269,10 +271,10 @@ update_program(struct gl_context *ctx) * come up, or matter. */ - if (shProg && shProg->LinkStatus && shProg->FragmentProgram) { + if (fsProg && fsProg->LinkStatus && fsProg->FragmentProgram) { /* Use shader programs */ _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current, - shProg->FragmentProgram); + fsProg->FragmentProgram); } else if (ctx->FragmentProgram._Enabled) { /* use user-defined vertex program */ @@ -292,10 +294,10 @@ update_program(struct gl_context *ctx) _mesa_reference_fragprog(ctx, &ctx->FragmentProgram._Current, NULL); } - if (shProg && shProg->LinkStatus && shProg->GeometryProgram) { + if (gsProg && gsProg->LinkStatus && gsProg->GeometryProgram) { /* Use shader programs */ _mesa_reference_geomprog(ctx, &ctx->GeometryProgram._Current, - shProg->GeometryProgram); + gsProg->GeometryProgram); } else { /* no fragment program */ _mesa_reference_geomprog(ctx, &ctx->GeometryProgram._Current, NULL); @@ -305,10 +307,10 @@ update_program(struct gl_context *ctx) * _mesa_get_fixed_func_vertex_program() needs to know active * fragprog inputs. */ - if (shProg && shProg->LinkStatus && shProg->VertexProgram) { + if (vsProg && vsProg->LinkStatus && vsProg->VertexProgram) { /* Use shader programs */ _mesa_reference_vertprog(ctx, &ctx->VertexProgram._Current, - shProg->VertexProgram); + vsProg->VertexProgram); } else if (ctx->VertexProgram._Enabled) { /* use user-defined vertex program */ diff --git a/src/mesa/main/texenvprogram.c b/src/mesa/main/texenvprogram.c index 4647a9c4405..a8bffe416d9 100644 --- a/src/mesa/main/texenvprogram.c +++ b/src/mesa/main/texenvprogram.c @@ -310,9 +310,10 @@ static GLuint translate_tex_src_bit( GLbitfield bit ) static GLbitfield get_fp_input_mask( struct gl_context *ctx ) { /* _NEW_PROGRAM */ - const GLboolean vertexShader = (ctx->Shader.CurrentProgram && - ctx->Shader.CurrentProgram->LinkStatus && - ctx->Shader.CurrentProgram->VertexProgram); + const GLboolean vertexShader = + (ctx->Shader.CurrentVertexProgram && + ctx->Shader.CurrentVertexProgram->LinkStatus && + ctx->Shader.CurrentVertexProgram->VertexProgram); const GLboolean vertexProgram = ctx->VertexProgram._Enabled; GLbitfield fp_inputs = 0x0; @@ -377,7 +378,7 @@ static GLbitfield get_fp_input_mask( struct gl_context *ctx ) * validation (see additional comments in state.c). */ if (vertexShader) - vprog = ctx->Shader.CurrentProgram->VertexProgram; + vprog = ctx->Shader.CurrentVertexProgram->VertexProgram; else vprog = ctx->VertexProgram.Current; diff --git a/src/mesa/main/texstate.c b/src/mesa/main/texstate.c index 1b0d760fae5..f4d77189f29 100644 --- a/src/mesa/main/texstate.c +++ b/src/mesa/main/texstate.c @@ -496,23 +496,28 @@ update_texture_state( struct gl_context *ctx ) struct gl_vertex_program *vprog = NULL; GLbitfield enabledFragUnits = 0x0; - if (ctx->Shader.CurrentProgram && - ctx->Shader.CurrentProgram->LinkStatus) { - fprog = ctx->Shader.CurrentProgram->FragmentProgram; - vprog = ctx->Shader.CurrentProgram->VertexProgram; + if (ctx->Shader.CurrentVertexProgram && + ctx->Shader.CurrentVertexProgram->LinkStatus) { + vprog = ctx->Shader.CurrentVertexProgram->VertexProgram; + } else if (ctx->VertexProgram._Enabled) { + /* XXX enable this if/when non-shader vertex programs get + * texture fetches: + vprog = ctx->VertexProgram.Current; + */ } - else { - if (ctx->FragmentProgram._Enabled) { - fprog = ctx->FragmentProgram.Current; - } - if (ctx->VertexProgram._Enabled) { - /* XXX enable this if/when non-shader vertex programs get - * texture fetches: - vprog = ctx->VertexProgram.Current; - */ - } + + if (ctx->Shader.CurrentFragmentProgram && + ctx->Shader.CurrentFragmentProgram->LinkStatus) { + fprog = ctx->Shader.CurrentFragmentProgram->FragmentProgram; + } + else if (ctx->FragmentProgram._Enabled) { + fprog = ctx->FragmentProgram.Current; } + /* FINISHME: Geometry shader texture accesses should also be considered + * FINISHME: here. + */ + /* TODO: only set this if there are actual changes */ ctx->NewState |= _NEW_TEXTURE; |