/**
* 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
*/
return false;
}
+ prog->Vert.ClipDistanceArraySize = 0;
+
if (prog->Version >= 130) {
/* From section 7.1 (Vertex Shader Special Variables) of the
* GLSL 1.30 spec:
return false;
}
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;
*/
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;
}
/**
*/
unsigned num_components() const
{
- if (this->single_component == -1)
- return this->vector_elements * this->matrix_columns * this->size;
+ if (this->is_clip_distance_mesa)
+ return this->size;
else
- return 1;
+ return this->vector_elements * this->matrix_columns * this->size;
}
private:
unsigned array_subscript;
/**
- * Which component to extract from the vertex shader output location that
- * the linker assigned to this variable. -1 if all components should be
- * extracted.
+ * True if the variable is gl_ClipDistance and the driver lowers
+ * gl_ClipDistance to gl_ClipDistanceMESA.
*/
- int single_component;
+ bool is_clip_distance_mesa;
/**
* The vertex shader output location that the linker assigned for this
this->location = -1;
this->orig_name = input;
- this->single_component = -1;
+ this->is_clip_distance_mesa = false;
const char *bracket = strrchr(input, '[');
this->is_subscripted = false;
}
- /* For drivers that lower gl_ClipDistance to gl_ClipDistanceMESA, we need
- * to convert a request for gl_ClipDistance[n] into a request for a
- * component of gl_ClipDistanceMESA[n/4].
+ /* For drivers that lower gl_ClipDistance to gl_ClipDistanceMESA, this
+ * class must behave specially to account for the fact that gl_ClipDistance
+ * is converted from a float[8] to a vec4[2].
*/
if (ctx->ShaderCompilerOptions[MESA_SHADER_VERTEX].LowerClipDistance &&
strcmp(this->var_name, "gl_ClipDistance") == 0) {
- this->var_name = "gl_ClipDistanceMESA";
- if (this->is_subscripted) {
- this->single_component = this->array_subscript % 4;
- this->array_subscript /= 4;
- }
+ this->is_clip_distance_mesa = true;
}
return true;
return false;
if (x.is_subscripted && x.array_subscript != y.array_subscript)
return false;
- if (x.single_component != y.single_component)
- return false;
return true;
}
/* Array variable */
const unsigned matrix_cols =
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) {
/* Check array bounds. */
- if (this->array_subscript >=
- (unsigned) output_var->type->array_size()) {
+ if (this->array_subscript >= actual_array_size) {
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,
- output_var->type->array_size());
+ actual_array_size);
return false;
}
- this->location =
- output_var->location + this->array_subscript * matrix_cols;
+ if (this->is_clip_distance_mesa) {
+ this->location =
+ output_var->location + this->array_subscript / 4;
+ } else {
+ this->location =
+ output_var->location + this->array_subscript * matrix_cols;
+ }
this->size = 1;
} else {
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->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 {
/* Regular variable (scalar, vector, or matrix) */
if (this->is_subscripted) {
this->matrix_columns = output_var->type->matrix_columns;
this->type = output_var->type->gl_type;
}
+
/* From GL_EXT_transform_feedback:
* A program will fail to link if:
*
this->orig_name);
return false;
}
+ unsigned translated_size = this->size;
+ if (this->is_clip_distance_mesa)
+ translated_size = (translated_size + 3) / 4;
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) {
- unsigned num_components =
- this->single_component >= 0 ? 1 : this->vector_elements;
+ unsigned num_components = 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 =
this->location + v + index * this->matrix_columns;
info->Outputs[info->NumOutputs].NumComponents = num_components;
info->Outputs[info->NumOutputs].OutputBuffer = 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->BufferStride[buffer] += num_components;
components_so_far += num_components;