summaryrefslogtreecommitdiffstats
path: root/src/glsl/linker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/glsl/linker.cpp')
-rw-r--r--src/glsl/linker.cpp64
1 files changed, 40 insertions, 24 deletions
diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp
index adedfe6f33a..509575192e7 100644
--- a/src/glsl/linker.cpp
+++ b/src/glsl/linker.cpp
@@ -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;
}