glsl/linker: Refactor in preparation for adding more shader stages.
Rather than maintain separately named arrays and counts for vertex, geometry, and fragment shaders, just maintain these as arrays indexed by the gl_shader_type enum. v2: When there is neither a vertex nor a geometry shader, set prog->LastClipDistanceArraySize = 0, and clarify that the values is not used. Reviewed-by: Chris Forbes <chrisf@ijw.co.nz> Reviewed-by: Brian Paul <brianp@vmware.com>
This commit is contained in:
@@ -1996,19 +1996,14 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
|
||||
|
||||
/* Separate the shaders into groups based on their type.
|
||||
*/
|
||||
struct gl_shader **vert_shader_list;
|
||||
unsigned num_vert_shaders = 0;
|
||||
struct gl_shader **frag_shader_list;
|
||||
unsigned num_frag_shaders = 0;
|
||||
struct gl_shader **geom_shader_list;
|
||||
unsigned num_geom_shaders = 0;
|
||||
struct gl_shader **shader_list[MESA_SHADER_STAGES];
|
||||
unsigned num_shaders[MESA_SHADER_STAGES];
|
||||
|
||||
vert_shader_list = (struct gl_shader **)
|
||||
calloc(prog->NumShaders, sizeof(struct gl_shader *));
|
||||
frag_shader_list = (struct gl_shader **)
|
||||
calloc(prog->NumShaders, sizeof(struct gl_shader *));
|
||||
geom_shader_list = (struct gl_shader **)
|
||||
for (int i = 0; i < MESA_SHADER_STAGES; i++) {
|
||||
shader_list[i] = (struct gl_shader **)
|
||||
calloc(prog->NumShaders, sizeof(struct gl_shader *));
|
||||
num_shaders[i] = 0;
|
||||
}
|
||||
|
||||
unsigned min_version = UINT_MAX;
|
||||
unsigned max_version = 0;
|
||||
@@ -2024,20 +2019,9 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch (prog->Shaders[i]->Stage) {
|
||||
case MESA_SHADER_VERTEX:
|
||||
vert_shader_list[num_vert_shaders] = prog->Shaders[i];
|
||||
num_vert_shaders++;
|
||||
break;
|
||||
case MESA_SHADER_FRAGMENT:
|
||||
frag_shader_list[num_frag_shaders] = prog->Shaders[i];
|
||||
num_frag_shaders++;
|
||||
break;
|
||||
case MESA_SHADER_GEOMETRY:
|
||||
geom_shader_list[num_geom_shaders] = prog->Shaders[i];
|
||||
num_geom_shaders++;
|
||||
break;
|
||||
}
|
||||
gl_shader_stage shader_type = prog->Shaders[i]->Stage;
|
||||
shader_list[shader_type][num_shaders[shader_type]] = prog->Shaders[i];
|
||||
num_shaders[shader_type]++;
|
||||
}
|
||||
|
||||
/* In desktop GLSL, different shader versions may be linked together. In
|
||||
@@ -2054,7 +2038,8 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
|
||||
|
||||
/* Geometry shaders have to be linked with vertex shaders.
|
||||
*/
|
||||
if (num_geom_shaders > 0 && num_vert_shaders == 0) {
|
||||
if (num_shaders[MESA_SHADER_GEOMETRY] > 0 &&
|
||||
num_shaders[MESA_SHADER_VERTEX] == 0) {
|
||||
linker_error(prog, "Geometry shader must be linked with "
|
||||
"vertex shader\n");
|
||||
goto done;
|
||||
@@ -2069,55 +2054,39 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
|
||||
|
||||
/* Link all shaders for a particular stage and validate the result.
|
||||
*/
|
||||
if (num_vert_shaders > 0) {
|
||||
for (int stage = 0; stage < MESA_SHADER_STAGES; stage++) {
|
||||
if (num_shaders[stage] > 0) {
|
||||
gl_shader *const sh =
|
||||
link_intrastage_shaders(mem_ctx, ctx, prog, vert_shader_list,
|
||||
num_vert_shaders);
|
||||
link_intrastage_shaders(mem_ctx, ctx, prog, shader_list[stage],
|
||||
num_shaders[stage]);
|
||||
|
||||
if (!prog->LinkStatus)
|
||||
goto done;
|
||||
|
||||
switch (stage) {
|
||||
case MESA_SHADER_VERTEX:
|
||||
validate_vertex_shader_executable(prog, sh);
|
||||
if (!prog->LinkStatus)
|
||||
goto done;
|
||||
prog->LastClipDistanceArraySize = prog->Vert.ClipDistanceArraySize;
|
||||
|
||||
_mesa_reference_shader(ctx, &prog->_LinkedShaders[MESA_SHADER_VERTEX],
|
||||
sh);
|
||||
}
|
||||
|
||||
if (num_frag_shaders > 0) {
|
||||
gl_shader *const sh =
|
||||
link_intrastage_shaders(mem_ctx, ctx, prog, frag_shader_list,
|
||||
num_frag_shaders);
|
||||
|
||||
if (!prog->LinkStatus)
|
||||
goto done;
|
||||
|
||||
validate_fragment_shader_executable(prog, sh);
|
||||
if (!prog->LinkStatus)
|
||||
goto done;
|
||||
|
||||
_mesa_reference_shader(ctx, &prog->_LinkedShaders[MESA_SHADER_FRAGMENT],
|
||||
sh);
|
||||
}
|
||||
|
||||
if (num_geom_shaders > 0) {
|
||||
gl_shader *const sh =
|
||||
link_intrastage_shaders(mem_ctx, ctx, prog, geom_shader_list,
|
||||
num_geom_shaders);
|
||||
|
||||
if (!prog->LinkStatus)
|
||||
goto done;
|
||||
|
||||
break;
|
||||
case MESA_SHADER_GEOMETRY:
|
||||
validate_geometry_shader_executable(prog, sh);
|
||||
break;
|
||||
case MESA_SHADER_FRAGMENT:
|
||||
validate_fragment_shader_executable(prog, sh);
|
||||
break;
|
||||
}
|
||||
if (!prog->LinkStatus)
|
||||
goto done;
|
||||
prog->LastClipDistanceArraySize = prog->Geom.ClipDistanceArraySize;
|
||||
|
||||
_mesa_reference_shader(ctx, &prog->_LinkedShaders[MESA_SHADER_GEOMETRY],
|
||||
sh);
|
||||
_mesa_reference_shader(ctx, &prog->_LinkedShaders[stage], sh);
|
||||
}
|
||||
}
|
||||
|
||||
if (num_shaders[MESA_SHADER_GEOMETRY] > 0)
|
||||
prog->LastClipDistanceArraySize = prog->Geom.ClipDistanceArraySize;
|
||||
else if (num_shaders[MESA_SHADER_VERTEX] > 0)
|
||||
prog->LastClipDistanceArraySize = prog->Vert.ClipDistanceArraySize;
|
||||
else
|
||||
prog->LastClipDistanceArraySize = 0; /* Not used */
|
||||
|
||||
/* Here begins the inter-stage linking phase. Some initial validation is
|
||||
* performed, then locations are assigned for uniforms, attributes, and
|
||||
@@ -2375,11 +2344,8 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
|
||||
/* FINISHME: Assign fragment shader output locations. */
|
||||
|
||||
done:
|
||||
free(vert_shader_list);
|
||||
free(frag_shader_list);
|
||||
free(geom_shader_list);
|
||||
|
||||
for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
|
||||
free(shader_list[i]);
|
||||
if (prog->_LinkedShaders[i] == NULL)
|
||||
continue;
|
||||
|
||||
|
Reference in New Issue
Block a user