/** * Free all the data that hangs off a shader program object, but not the * object itself. */ void _mesa_free_shader_program_data(GLcontext *ctx, struct gl_shader_program *shProg) { GLuint i; assert(shProg->Type == GL_SHADER_PROGRAM_MESA); _mesa_clear_shader_program_data(ctx, shProg); if (shProg->Attributes) { _mesa_free_parameter_list(shProg->Attributes); shProg->Attributes = NULL; } /* detach shaders */ for (i = 0; i < shProg->NumShaders; i++) { _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL); } shProg->NumShaders = 0; if (shProg->Shaders) { _mesa_free(shProg->Shaders); shProg->Shaders = NULL; } if (shProg->InfoLog) { _mesa_free(shProg->InfoLog); shProg->InfoLog = NULL; } }
/** * Free all the data that hangs off a shader program object, but not the * object itself. */ void _mesa_free_shader_program_data(struct gl_context *ctx, struct gl_shader_program *shProg) { GLuint i; gl_shader_stage sh; assert(shProg->Type == GL_SHADER_PROGRAM_MESA); _mesa_clear_shader_program_data(shProg); if (shProg->AttributeBindings) { string_to_uint_map_dtor(shProg->AttributeBindings); shProg->AttributeBindings = NULL; } if (shProg->FragDataBindings) { string_to_uint_map_dtor(shProg->FragDataBindings); shProg->FragDataBindings = NULL; } if (shProg->FragDataIndexBindings) { string_to_uint_map_dtor(shProg->FragDataIndexBindings); shProg->FragDataIndexBindings = NULL; } /* detach shaders */ for (i = 0; i < shProg->NumShaders; i++) { _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL); } shProg->NumShaders = 0; free(shProg->Shaders); shProg->Shaders = NULL; /* Transform feedback varying vars */ for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) { free(shProg->TransformFeedback.VaryingNames[i]); } free(shProg->TransformFeedback.VaryingNames); shProg->TransformFeedback.VaryingNames = NULL; shProg->TransformFeedback.NumVarying = 0; for (sh = 0; sh < MESA_SHADER_STAGES; sh++) { if (shProg->_LinkedShaders[sh] != NULL) { _mesa_delete_shader(ctx, shProg->_LinkedShaders[sh]); shProg->_LinkedShaders[sh] = NULL; } } free(shProg->Label); shProg->Label = NULL; }
/** * Shader linker. Currently: * * 1. The last attached vertex shader and fragment shader are linked. * 2. Varying vars in the two shaders are combined so their locations * agree between the vertex and fragment stages. They're treated as * vertex program output attribs and as fragment program input attribs. * 3. The vertex and fragment programs are cloned and modified to update * src/dst register references so they use the new, linked varying * storage locations. */ void _slang_link(GLcontext *ctx, GLhandleARB programObj, struct gl_shader_program *shProg) { const struct gl_vertex_program *vertProg = NULL; const struct gl_fragment_program *fragProg = NULL; GLboolean vertNotify = GL_TRUE, fragNotify = GL_TRUE; GLuint numSamplers = 0; GLuint i; _mesa_clear_shader_program_data(ctx, shProg); /* Initialize LinkStatus to "success". Will be cleared if error. */ shProg->LinkStatus = GL_TRUE; /* check that all programs compiled successfully */ for (i = 0; i < shProg->NumShaders; i++) { if (!shProg->Shaders[i]->CompileStatus) { link_error(shProg, "linking with uncompiled shader\n"); return; } } shProg->Uniforms = _mesa_new_uniform_list(); shProg->Varying = _mesa_new_parameter_list(); /* * Find the vertex and fragment shaders which define main() */ { struct gl_shader *vertShader, *fragShader; vertShader = get_main_shader(ctx, shProg, GL_VERTEX_SHADER); fragShader = get_main_shader(ctx, shProg, GL_FRAGMENT_SHADER); if (vertShader) vertProg = vertex_program(vertShader->Program); if (fragShader) fragProg = fragment_program(fragShader->Program); if (!shProg->LinkStatus) return; } #if FEATURE_es2_glsl /* must have both a vertex and fragment program for ES2 */ if (!vertProg) { link_error(shProg, "missing vertex shader\n"); return; } if (!fragProg) { link_error(shProg, "missing fragment shader\n"); return; } #endif /* * Make copies of the vertex/fragment programs now since we'll be * changing src/dst registers after merging the uniforms and varying vars. */ _mesa_reference_vertprog(ctx, &shProg->VertexProgram, NULL); if (vertProg) { struct gl_vertex_program *linked_vprog = _mesa_clone_vertex_program(ctx, vertProg); shProg->VertexProgram = linked_vprog; /* refcount OK */ /* vertex program ID not significant; just set Id for debugging purposes */ shProg->VertexProgram->Base.Id = shProg->Name; ASSERT(shProg->VertexProgram->Base.RefCount == 1); } _mesa_reference_fragprog(ctx, &shProg->FragmentProgram, NULL); if (fragProg) { struct gl_fragment_program *linked_fprog = _mesa_clone_fragment_program(ctx, fragProg); shProg->FragmentProgram = linked_fprog; /* refcount OK */ /* vertex program ID not significant; just set Id for debugging purposes */ shProg->FragmentProgram->Base.Id = shProg->Name; ASSERT(shProg->FragmentProgram->Base.RefCount == 1); } /* link varying vars */ if (shProg->VertexProgram) { if (!link_varying_vars(ctx, shProg, &shProg->VertexProgram->Base)) return; } if (shProg->FragmentProgram) { if (!link_varying_vars(ctx, shProg, &shProg->FragmentProgram->Base)) return; } /* link uniform vars */ if (shProg->VertexProgram) { if (!link_uniform_vars(ctx, shProg, &shProg->VertexProgram->Base, &numSamplers)) { return; } } if (shProg->FragmentProgram) { if (!link_uniform_vars(ctx, shProg, &shProg->FragmentProgram->Base, &numSamplers)) { return; } } /*_mesa_print_uniforms(shProg->Uniforms);*/ if (shProg->VertexProgram) { if (!_slang_resolve_attributes(shProg, &vertProg->Base, &shProg->VertexProgram->Base)) { return; } } if (shProg->VertexProgram) { _slang_update_inputs_outputs(&shProg->VertexProgram->Base); _slang_count_temporaries(&shProg->VertexProgram->Base); if (!(shProg->VertexProgram->Base.OutputsWritten & BITFIELD64_BIT(VERT_RESULT_HPOS))) { /* the vertex program did not compute a vertex position */ link_error(shProg, "gl_Position was not written by vertex shader\n"); return; } } if (shProg->FragmentProgram) { _slang_count_temporaries(&shProg->FragmentProgram->Base); _slang_update_inputs_outputs(&shProg->FragmentProgram->Base); } /* Check that all the varying vars needed by the fragment shader are * actually produced by the vertex shader. */ if (shProg->FragmentProgram) { const GLbitfield varyingRead = shProg->FragmentProgram->Base.InputsRead >> FRAG_ATTRIB_VAR0; const GLbitfield64 varyingWritten = shProg->VertexProgram ? shProg->VertexProgram->Base.OutputsWritten >> VERT_RESULT_VAR0 : 0x0; if ((varyingRead & varyingWritten) != varyingRead) { link_error(shProg, "Fragment program using varying vars not written by vertex shader\n"); return; } } /* check that gl_FragColor and gl_FragData are not both written to */ if (shProg->FragmentProgram) { const GLbitfield64 outputsWritten = shProg->FragmentProgram->Base.OutputsWritten; if ((outputsWritten & BITFIELD64_BIT(FRAG_RESULT_COLOR)) && (outputsWritten >= BITFIELD64_BIT(FRAG_RESULT_DATA0))) { link_error(shProg, "Fragment program cannot write both gl_FragColor" " and gl_FragData[].\n"); return; } } if (fragProg && shProg->FragmentProgram) { /* Compute initial program's TexturesUsed info */ _mesa_update_shader_textures_used(&shProg->FragmentProgram->Base); /* notify driver that a new fragment program has been compiled/linked */ vertNotify = ctx->Driver.ProgramStringNotify(ctx, GL_FRAGMENT_PROGRAM_ARB, &shProg->FragmentProgram->Base); if (ctx->Shader.Flags & GLSL_DUMP) { printf("Mesa pre-link fragment program:\n"); _mesa_print_program(&fragProg->Base); _mesa_print_program_parameters(ctx, &fragProg->Base); printf("Mesa post-link fragment program:\n"); _mesa_print_program(&shProg->FragmentProgram->Base); _mesa_print_program_parameters(ctx, &shProg->FragmentProgram->Base); } } if (vertProg && shProg->VertexProgram) { /* Compute initial program's TexturesUsed info */ _mesa_update_shader_textures_used(&shProg->VertexProgram->Base); /* notify driver that a new vertex program has been compiled/linked */ fragNotify = ctx->Driver.ProgramStringNotify(ctx, GL_VERTEX_PROGRAM_ARB, &shProg->VertexProgram->Base); if (ctx->Shader.Flags & GLSL_DUMP) { printf("Mesa pre-link vertex program:\n"); _mesa_print_program(&vertProg->Base); _mesa_print_program_parameters(ctx, &vertProg->Base); printf("Mesa post-link vertex program:\n"); _mesa_print_program(&shProg->VertexProgram->Base); _mesa_print_program_parameters(ctx, &shProg->VertexProgram->Base); } } /* Debug: */ if (0) { if (shProg->VertexProgram) _mesa_postprocess_program(ctx, &shProg->VertexProgram->Base); if (shProg->FragmentProgram) _mesa_postprocess_program(ctx, &shProg->FragmentProgram->Base); } if (ctx->Shader.Flags & GLSL_DUMP) { printf("Varying vars:\n"); _mesa_print_parameter_list(shProg->Varying); if (shProg->InfoLog) { printf("Info Log: %s\n", shProg->InfoLog); } } if (!vertNotify || !fragNotify) { /* driver rejected one/both of the vertex/fragment programs */ if (!shProg->InfoLog) { link_error(shProg, "Vertex and/or fragment program rejected by driver\n"); } } else { shProg->LinkStatus = (shProg->VertexProgram || shProg->FragmentProgram); } }