mesa: allocate transform_feedback_info::Outputs array dynamically

The nvc0 gallium driver is advertising 128 MAX_INTERLEAVED_COMPS
which made it always assert in the linker when TFB was used since
the Outputs array was smaller than that maximum.

v2: added assertions

NOTE: This is a candidate for the 8.0 branch.

Reviewed-by: Paul Berry <stereotype441@gmail.com>
This commit is contained in:
Christoph Bumiller 2012-01-20 13:24:46 +01:00
parent c96b983403
commit d540af554a
2 changed files with 57 additions and 39 deletions

View file

@ -1388,9 +1388,10 @@ public:
static bool is_same(const tfeedback_decl &x, const tfeedback_decl &y);
bool assign_location(struct gl_context *ctx, struct gl_shader_program *prog,
ir_variable *output_var);
bool accumulate_num_outputs(struct gl_shader_program *prog, unsigned *count);
bool store(struct gl_context *ctx, struct gl_shader_program *prog,
struct gl_transform_feedback_info *info, unsigned buffer,
unsigned varying) const;
unsigned varying, const unsigned max_outputs) const;
/**
@ -1624,16 +1625,9 @@ tfeedback_decl::assign_location(struct gl_context *ctx,
}
/**
* Update gl_transform_feedback_info to reflect this tfeedback_decl.
*
* If an error occurs, the error is reported through linker_error() and false
* is returned.
*/
bool
tfeedback_decl::store(struct gl_context *ctx, struct gl_shader_program *prog,
struct gl_transform_feedback_info *info,
unsigned buffer, unsigned varying) const
tfeedback_decl::accumulate_num_outputs(struct gl_shader_program *prog,
unsigned *count)
{
if (!this->is_assigned()) {
/* From GL_EXT_transform_feedback:
@ -1648,6 +1642,28 @@ tfeedback_decl::store(struct gl_context *ctx, struct gl_shader_program *prog,
return false;
}
unsigned translated_size = this->size;
if (this->is_clip_distance_mesa)
translated_size = (translated_size + 3) / 4;
*count += translated_size * this->matrix_columns;
return true;
}
/**
* Update gl_transform_feedback_info to reflect this tfeedback_decl.
*
* If an error occurs, the error is reported through linker_error() and false
* is returned.
*/
bool
tfeedback_decl::store(struct gl_context *ctx, struct gl_shader_program *prog,
struct gl_transform_feedback_info *info,
unsigned buffer,
unsigned varying, const unsigned max_outputs) const
{
/* From GL_EXT_transform_feedback:
* A program will fail to link if:
*
@ -1663,19 +1679,6 @@ tfeedback_decl::store(struct gl_context *ctx, struct gl_shader_program *prog,
return false;
}
/* Verify that the checks on MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS
* and MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS are sufficient to prevent
* overflow of info->Outputs[]. In worst case we generate one entry in
* Outputs[] per component so a conservative check is to verify that the
* size of the array is greater than or equal to both
* MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS and
* MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS.
*/
assert(Elements(info->Outputs) >=
ctx->Const.MaxTransformFeedbackInterleavedComponents);
assert(Elements(info->Outputs) >=
ctx->Const.MaxTransformFeedbackSeparateComponents);
unsigned translated_size = this->size;
if (this->is_clip_distance_mesa)
translated_size = (translated_size + 3) / 4;
@ -1683,6 +1686,7 @@ tfeedback_decl::store(struct gl_context *ctx, struct gl_shader_program *prog,
for (unsigned index = 0; index < translated_size; ++index) {
for (unsigned v = 0; v < this->matrix_columns; ++v) {
unsigned num_components = this->vector_elements;
assert(info->NumOutputs < max_outputs);
info->Outputs[info->NumOutputs].ComponentOffset = 0;
if (this->is_clip_distance_mesa) {
if (this->is_subscripted) {
@ -1976,6 +1980,7 @@ store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog,
prog->TransformFeedback.BufferMode == GL_SEPARATE_ATTRIBS;
ralloc_free(prog->LinkedTransformFeedback.Varyings);
ralloc_free(prog->LinkedTransformFeedback.Outputs);
memset(&prog->LinkedTransformFeedback, 0,
sizeof(prog->LinkedTransformFeedback));
@ -1988,12 +1993,23 @@ store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog,
struct gl_transform_feedback_varying_info,
num_tfeedback_decls);
unsigned num_outputs = 0;
for (unsigned i = 0; i < num_tfeedback_decls; ++i)
if (!tfeedback_decls[i].accumulate_num_outputs(prog, &num_outputs))
return false;
prog->LinkedTransformFeedback.Outputs =
rzalloc_array(prog,
struct gl_transform_feedback_output,
num_outputs);
for (unsigned i = 0; i < num_tfeedback_decls; ++i) {
unsigned buffer = separate_attribs_mode ? i : 0;
if (!tfeedback_decls[i].store(ctx, prog, &prog->LinkedTransformFeedback,
buffer, i))
buffer, i, num_outputs))
return false;
}
assert(prog->LinkedTransformFeedback.NumOutputs == num_outputs);
return true;
}

View file

@ -1827,6 +1827,22 @@ struct gl_transform_feedback_varying_info {
GLint Size;
};
struct gl_transform_feedback_output {
unsigned OutputRegister;
unsigned OutputBuffer;
unsigned NumComponents;
/** offset (in DWORDs) of this output within the interleaved structure */
unsigned DstOffset;
/**
* Offset into the output register of the data to output. For example,
* if NumComponents is 2 and ComponentOffset is 1, then the data to
* offset is in the y and z components of the output register.
*/
unsigned ComponentOffset;
};
/** Post-link transform feedback info. */
struct gl_transform_feedback_info {
unsigned NumOutputs;
@ -1836,21 +1852,7 @@ struct gl_transform_feedback_info {
*/
unsigned NumBuffers;
struct {
unsigned OutputRegister;
unsigned OutputBuffer;
unsigned NumComponents;
/** offset (in DWORDs) of this output within the interleaved structure */
unsigned DstOffset;
/**
* Offset into the output register of the data to output. For example,
* if NumComponents is 2 and ComponentOffset is 1, then the data to
* offset is in the y and z components of the output register.
*/
unsigned ComponentOffset;
} Outputs[MAX_PROGRAM_OUTPUTS];
struct gl_transform_feedback_output *Outputs;
/** Transform feedback varyings used for the linking of this shader program.
*