mesa: Fix transform feedback of unsubscripted gl_ClipDistance array.

On drivers that set gl_shader_compiler_options::LowerClipDistance (for
example i965), we need to handle transform feedback of gl_ClipDistance
specially, to account for the fact that the hardware represents it as
an array of vec4's rather than an array of floats.

The previous way this was accounted for (translating the request for
gl_ClipDistance[n] to a request for a component of
gl_ClipDistanceMESA[n/4]) doesn't work when performing transform
feedback on the whole unsubscripted array, because we need to keep
track of the size of the gl_ClipDistance array prior to the lowering
pass.  So I replaced it with a boolean is_clip_distance_mesa, which
switches on the special logic that is needed to handle the lowered
version of gl_ClipDistance.

Fixes Piglit tests "EXT_transform_feedback/builtin-varyings
gl_ClipDistance[{1,2,3,5,6,7}]-no-subscript".

Reviewed-by: Eric Anholt <eric@anholt.net>
This commit is contained in:
Paul Berry 2012-01-04 13:57:52 -08:00
parent be4e9f7a0c
commit 642e5b413e
2 changed files with 58 additions and 33 deletions

View File

@ -246,7 +246,8 @@ count_attribute_slots(const glsl_type *t)
/** /**
* Verify that a vertex shader executable meets all semantic requirements. * Verify that a vertex shader executable meets all semantic requirements.
* *
* Also sets prog->Vert.UsesClipDistance as a side effect. * Also sets prog->Vert.UsesClipDistance and prog->Vert.ClipDistanceArraySize
* as a side effect.
* *
* \param shader Vertex shader executable to be verified * \param shader Vertex shader executable to be verified
*/ */
@ -264,6 +265,8 @@ validate_vertex_shader_executable(struct gl_shader_program *prog,
return false; return false;
} }
prog->Vert.ClipDistanceArraySize = 0;
if (prog->Version >= 130) { if (prog->Version >= 130) {
/* From section 7.1 (Vertex Shader Special Variables) of the /* From section 7.1 (Vertex Shader Special Variables) of the
* GLSL 1.30 spec: * GLSL 1.30 spec:
@ -282,6 +285,10 @@ validate_vertex_shader_executable(struct gl_shader_program *prog,
return false; return false;
} }
prog->Vert.UsesClipDistance = clip_distance.variable_found(); prog->Vert.UsesClipDistance = clip_distance.variable_found();
ir_variable *clip_distance_var =
shader->symbols->get_variable("gl_ClipDistance");
if (clip_distance_var)
prog->Vert.ClipDistanceArraySize = clip_distance_var->type->length;
} }
return true; return true;
@ -1399,7 +1406,10 @@ public:
*/ */
bool matches_var(ir_variable *var) const bool matches_var(ir_variable *var) const
{ {
return strcmp(var->name, this->var_name) == 0; if (this->is_clip_distance_mesa)
return strcmp(var->name, "gl_ClipDistanceMESA") == 0;
else
return strcmp(var->name, this->var_name) == 0;
} }
/** /**
@ -1408,10 +1418,10 @@ public:
*/ */
unsigned num_components() const unsigned num_components() const
{ {
if (this->single_component == -1) if (this->is_clip_distance_mesa)
return this->vector_elements * this->matrix_columns * this->size; return this->size;
else else
return 1; return this->vector_elements * this->matrix_columns * this->size;
} }
private: private:
@ -1437,11 +1447,10 @@ private:
unsigned array_subscript; unsigned array_subscript;
/** /**
* Which component to extract from the vertex shader output location that * True if the variable is gl_ClipDistance and the driver lowers
* the linker assigned to this variable. -1 if all components should be * gl_ClipDistance to gl_ClipDistanceMESA.
* extracted.
*/ */
int single_component; bool is_clip_distance_mesa;
/** /**
* The vertex shader output location that the linker assigned for this * The vertex shader output location that the linker assigned for this
@ -1487,7 +1496,7 @@ tfeedback_decl::init(struct gl_context *ctx, struct gl_shader_program *prog,
this->location = -1; this->location = -1;
this->orig_name = input; this->orig_name = input;
this->single_component = -1; this->is_clip_distance_mesa = false;
const char *bracket = strrchr(input, '['); const char *bracket = strrchr(input, '[');
@ -1503,17 +1512,13 @@ tfeedback_decl::init(struct gl_context *ctx, struct gl_shader_program *prog,
this->is_subscripted = false; this->is_subscripted = false;
} }
/* For drivers that lower gl_ClipDistance to gl_ClipDistanceMESA, we need /* For drivers that lower gl_ClipDistance to gl_ClipDistanceMESA, this
* to convert a request for gl_ClipDistance[n] into a request for a * class must behave specially to account for the fact that gl_ClipDistance
* component of gl_ClipDistanceMESA[n/4]. * is converted from a float[8] to a vec4[2].
*/ */
if (ctx->ShaderCompilerOptions[MESA_SHADER_VERTEX].LowerClipDistance && if (ctx->ShaderCompilerOptions[MESA_SHADER_VERTEX].LowerClipDistance &&
strcmp(this->var_name, "gl_ClipDistance") == 0) { strcmp(this->var_name, "gl_ClipDistance") == 0) {
this->var_name = "gl_ClipDistanceMESA"; this->is_clip_distance_mesa = true;
if (this->is_subscripted) {
this->single_component = this->array_subscript % 4;
this->array_subscript /= 4;
}
} }
return true; return true;
@ -1533,8 +1538,6 @@ tfeedback_decl::is_same(const tfeedback_decl &x, const tfeedback_decl &y)
return false; return false;
if (x.is_subscripted && x.array_subscript != y.array_subscript) if (x.is_subscripted && x.array_subscript != y.array_subscript)
return false; return false;
if (x.single_component != y.single_component)
return false;
return true; return true;
} }
@ -1555,27 +1558,36 @@ tfeedback_decl::assign_location(struct gl_context *ctx,
/* Array variable */ /* Array variable */
const unsigned matrix_cols = const unsigned matrix_cols =
output_var->type->fields.array->matrix_columns; output_var->type->fields.array->matrix_columns;
unsigned actual_array_size = this->is_clip_distance_mesa ?
prog->Vert.ClipDistanceArraySize : output_var->type->array_size();
if (this->is_subscripted) { if (this->is_subscripted) {
/* Check array bounds. */ /* Check array bounds. */
if (this->array_subscript >= if (this->array_subscript >= actual_array_size) {
(unsigned) output_var->type->array_size()) {
linker_error(prog, "Transform feedback varying %s has index " linker_error(prog, "Transform feedback varying %s has index "
"%i, but the array size is %i.", "%i, but the array size is %u.",
this->orig_name, this->array_subscript, this->orig_name, this->array_subscript,
output_var->type->array_size()); actual_array_size);
return false; return false;
} }
this->location = if (this->is_clip_distance_mesa) {
output_var->location + this->array_subscript * matrix_cols; this->location =
output_var->location + this->array_subscript / 4;
} else {
this->location =
output_var->location + this->array_subscript * matrix_cols;
}
this->size = 1; this->size = 1;
} else { } else {
this->location = output_var->location; this->location = output_var->location;
this->size = (unsigned) output_var->type->array_size(); this->size = actual_array_size;
} }
this->vector_elements = output_var->type->fields.array->vector_elements; this->vector_elements = output_var->type->fields.array->vector_elements;
this->matrix_columns = matrix_cols; this->matrix_columns = matrix_cols;
this->type = output_var->type->fields.array->gl_type; if (this->is_clip_distance_mesa)
this->type = GL_FLOAT;
else
this->type = output_var->type->fields.array->gl_type;
} else { } else {
/* Regular variable (scalar, vector, or matrix) */ /* Regular variable (scalar, vector, or matrix) */
if (this->is_subscripted) { if (this->is_subscripted) {
@ -1590,6 +1602,7 @@ tfeedback_decl::assign_location(struct gl_context *ctx,
this->matrix_columns = output_var->type->matrix_columns; this->matrix_columns = output_var->type->matrix_columns;
this->type = output_var->type->gl_type; this->type = output_var->type->gl_type;
} }
/* From GL_EXT_transform_feedback: /* From GL_EXT_transform_feedback:
* A program will fail to link if: * A program will fail to link if:
* *
@ -1634,18 +1647,28 @@ tfeedback_decl::store(struct gl_shader_program *prog,
this->orig_name); this->orig_name);
return false; return false;
} }
unsigned translated_size = this->size;
if (this->is_clip_distance_mesa)
translated_size = (translated_size + 3) / 4;
unsigned components_so_far = 0; unsigned components_so_far = 0;
for (unsigned index = 0; index < this->size; ++index) { for (unsigned index = 0; index < translated_size; ++index) {
for (unsigned v = 0; v < this->matrix_columns; ++v) { for (unsigned v = 0; v < this->matrix_columns; ++v) {
unsigned num_components = unsigned num_components = this->vector_elements;
this->single_component >= 0 ? 1 : this->vector_elements; info->Outputs[info->NumOutputs].ComponentOffset = 0;
if (this->is_clip_distance_mesa) {
if (this->is_subscripted) {
num_components = 1;
info->Outputs[info->NumOutputs].ComponentOffset =
this->array_subscript % 4;
} else {
num_components = MIN2(4, this->size - components_so_far);
}
}
info->Outputs[info->NumOutputs].OutputRegister = info->Outputs[info->NumOutputs].OutputRegister =
this->location + v + index * this->matrix_columns; this->location + v + index * this->matrix_columns;
info->Outputs[info->NumOutputs].NumComponents = num_components; info->Outputs[info->NumOutputs].NumComponents = num_components;
info->Outputs[info->NumOutputs].OutputBuffer = buffer; info->Outputs[info->NumOutputs].OutputBuffer = buffer;
info->Outputs[info->NumOutputs].DstOffset = info->BufferStride[buffer]; info->Outputs[info->NumOutputs].DstOffset = info->BufferStride[buffer];
info->Outputs[info->NumOutputs].ComponentOffset =
this->single_component >= 0 ? this->single_component : 0;
++info->NumOutputs; ++info->NumOutputs;
info->BufferStride[buffer] += num_components; info->BufferStride[buffer] += num_components;
components_so_far += num_components; components_so_far += num_components;

View File

@ -2277,6 +2277,8 @@ struct gl_shader_program
/** Vertex shader state - copied into gl_vertex_program at link time */ /** Vertex shader state - copied into gl_vertex_program at link time */
struct { struct {
GLboolean UsesClipDistance; /**< True if gl_ClipDistance is written to. */ GLboolean UsesClipDistance; /**< True if gl_ClipDistance is written to. */
GLuint ClipDistanceArraySize; /**< Size of the gl_ClipDistance array, or
0 if not present. */
} Vert; } Vert;
/* post-link info: */ /* post-link info: */