+ unsigned num_found;
+ find_variable * const *variables;
};
+/**
+ * Determine whether or not any of NULL-terminated list of variables
is ever
+ * written to.
+ */
+static void
+find_assignments(exec_list *ir, find_variable * const *vars)
+{
+ unsigned num_variables = 0;
+
+ for (find_variable * const *v = vars; *v; ++v)
+ num_variables++;
+
+ find_assignment_visitor visitor(num_variables, vars);
+ visitor.run(ir);
+}
+
+/**
+ * Determine whether or not the given variable is ever written to.
+ */
+static void
+find_assignments(exec_list *ir, find_variable *var)
+{
+ find_assignment_visitor visitor(1, &var);
+ visitor.run(ir);
+}
/**
* Visitor that determines whether or not a variable is ever read.
*/
class find_deref_visitor : public ir_hierarchical_visitor {
public:
find_deref_visitor(const char *name)
: name(name), found(false)
{
/* empty */
@@ -560,61 +598,62 @@ analyze_clip_cull_usage(struct gl_shader_program
*prog,
/* From section 7.1 (Vertex Shader Special Variables) of the
* GLSL 1.30 spec:
*
* "It is an error for a shader to statically write both
* gl_ClipVertex and gl_ClipDistance."
*
* This does not apply to GLSL ES shaders, since GLSL ES
defines neither
* gl_ClipVertex nor gl_ClipDistance. However with
* GL_EXT_clip_cull_distance, this functionality is exposed in
ES 3.0.
*/
- find_assignment_visitor clip_distance("gl_ClipDistance");
- find_assignment_visitor cull_distance("gl_CullDistance");
-
- clip_distance.run(shader->ir);
- cull_distance.run(shader->ir);
+ find_variable gl_ClipDistance("gl_ClipDistance");
+ find_variable gl_CullDistance("gl_CullDistance");
+ find_variable gl_ClipVertex("gl_ClipVertex");
+ find_variable * const variables[] = {
+ &gl_ClipDistance,
+ &gl_CullDistance,
+ !prog->IsES ? &gl_ClipVertex : NULL,
+ NULL
+ };
+ find_assignments(shader->ir, variables);
/* From the ARB_cull_distance spec:
*
* It is a compile-time or link-time error for the set of
shaders forming
* a program to statically read or write both gl_ClipVertex
and either
* gl_ClipDistance or gl_CullDistance.
*
* This does not apply to GLSL ES shaders, since GLSL ES
doesn't define
* gl_ClipVertex.
*/
if (!prog->IsES) {
- find_assignment_visitor clip_vertex("gl_ClipVertex");
-
- clip_vertex.run(shader->ir);
-
- if (clip_vertex.variable_found() &&
clip_distance.variable_found()) {
+ if (gl_ClipVertex.found && gl_ClipDistance.found) {
linker_error(prog, "%s shader writes to both
`gl_ClipVertex' "
"and `gl_ClipDistance'\n",
_mesa_shader_stage_to_string(shader->Stage));
return;
}
- if (clip_vertex.variable_found() &&
cull_distance.variable_found()) {
+ if (gl_ClipVertex.found && gl_CullDistance.found) {
linker_error(prog, "%s shader writes to both
`gl_ClipVertex' "
"and `gl_CullDistance'\n",
_mesa_shader_stage_to_string(shader->Stage));
return;
}
}
- if (clip_distance.variable_found()) {
+ if (gl_ClipDistance.found) {
ir_variable *clip_distance_var =
shader->symbols->get_variable("gl_ClipDistance");
assert(clip_distance_var);
*clip_distance_array_size = clip_distance_var->type->length;
}
- if (cull_distance.variable_found()) {
+ if (gl_CullDistance.found) {
ir_variable *cull_distance_var =
shader->symbols->get_variable("gl_CullDistance");
assert(cull_distance_var);
*cull_distance_array_size = cull_distance_var->type->length;
}
/* From the ARB_cull_distance spec:
*
* It is a compile-time or link-time error for the set of
shaders forming
* a program to have the sum of the sizes of the
gl_ClipDistance and
* gl_CullDistance arrays to be larger than
@@ -669,23 +708,23 @@ validate_vertex_shader_executable(struct
gl_shader_program *prog,
* after being written. This value will be used by primitive
* assembly, clipping, culling, and other fixed functionality
* operations, if present, that operate on primitives after
* vertex processing has occurred. Its value is undefined if
* the vertex shader executable does not write gl_Position."
*
* All GLSL ES Versions are similar to GLSL 1.40--failing to
write to
* gl_Position is not an error.
*/
if (prog->data->Version < (prog->IsES ? 300 : 140)) {
- find_assignment_visitor find("gl_Position");
- find.run(shader->ir);
- if (!find.variable_found()) {
+ find_variable gl_Position("gl_Position");
+ find_assignments(shader->ir, &gl_Position);
+ if (!gl_Position.found) {
if (prog->IsES) {
linker_warning(prog,
"vertex shader does not write to
`gl_Position'. "
"Its value is undefined. \n");
} else {
linker_error(prog,
"vertex shader does not write to
`gl_Position'. \n");
}
return;
}
@@ -715,27 +754,26 @@ validate_tess_eval_shader_executable(struct
gl_shader_program *prog,
*
* \param shader Fragment shader executable to be verified
*/
void
validate_fragment_shader_executable(struct gl_shader_program *prog,
struct gl_linked_shader *shader)
{
if (shader == NULL)
return;
- find_assignment_visitor frag_color("gl_FragColor");
- find_assignment_visitor frag_data("gl_FragData");
-
- frag_color.run(shader->ir);
- frag_data.run(shader->ir);
+ find_variable gl_FragColor("gl_FragColor");
+ find_variable gl_FragData("gl_FragData");
+ find_variable * const variables[] = { &gl_FragColor, &gl_FragData,
NULL };
+ find_assignments(shader->ir, variables);
- if (frag_color.variable_found() && frag_data.variable_found()) {
+ if (gl_FragColor.found && gl_FragData.found) {
linker_error(prog, "fragment shader writes to both "
"`gl_FragColor' and `gl_FragData'\n");
}
}
/**
* Verify that a geometry shader executable meets all semantic
requirements
*
* Also sets prog->Geom.VerticesIn, and
info.clip_distance_array_sizeand
* info.cull_distance_array_size as a side effect.