summaryrefslogtreecommitdiffstats
path: root/src/glsl
diff options
context:
space:
mode:
authorMarek Olšák <[email protected]>2011-12-18 02:39:34 +0100
committerMarek Olšák <[email protected]>2012-07-12 13:05:58 +0200
commit21cb5ed20d1d7984b7695395327ed0ba0b0d16e2 (patch)
treeed3ec91a9cd6e5085dfa166f003d14e703abf849 /src/glsl
parent9576d555e06df52a64906de94db4c1c7434630f9 (diff)
glsl: implement ARB_transform_feedback3 in the linker
Acked-by: Ian Romanick <[email protected]>
Diffstat (limited to 'src/glsl')
-rw-r--r--src/glsl/linker.cpp119
1 files changed, 104 insertions, 15 deletions
diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp
index 31094475216..f06298cf6e9 100644
--- a/src/glsl/linker.cpp
+++ b/src/glsl/linker.cpp
@@ -1439,8 +1439,7 @@ public:
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 max_outputs) const;
-
+ const unsigned max_outputs) const;
/**
* True if assign_location() has been called for this object.
@@ -1450,6 +1449,16 @@ public:
return this->location != -1;
}
+ bool is_next_buffer_separator() const
+ {
+ return this->next_buffer_separator;
+ }
+
+ bool is_varying() const
+ {
+ return !this->next_buffer_separator && !this->skip_components;
+ }
+
/**
* Determine whether this object refers to the variable var.
*/
@@ -1527,6 +1536,17 @@ private:
* glGetTransformFeedbackVarying().
*/
unsigned size;
+
+ /**
+ * How many components to skip. If non-zero, this is
+ * gl_SkipComponents{1,2,3,4} from ARB_transform_feedback3.
+ */
+ unsigned skip_components;
+
+ /**
+ * Whether this is gl_NextBuffer from ARB_transform_feedback3.
+ */
+ bool next_buffer_separator;
};
@@ -1546,7 +1566,31 @@ tfeedback_decl::init(struct gl_context *ctx, struct gl_shader_program *prog,
this->location = -1;
this->orig_name = input;
this->is_clip_distance_mesa = false;
+ this->skip_components = 0;
+ this->next_buffer_separator = false;
+ if (ctx->Extensions.ARB_transform_feedback3) {
+ /* Parse gl_NextBuffer. */
+ if (strcmp(input, "gl_NextBuffer") == 0) {
+ this->next_buffer_separator = true;
+ return true;
+ }
+
+ /* Parse gl_SkipComponents. */
+ if (strcmp(input, "gl_SkipComponents1") == 0)
+ this->skip_components = 1;
+ else if (strcmp(input, "gl_SkipComponents2") == 0)
+ this->skip_components = 2;
+ else if (strcmp(input, "gl_SkipComponents3") == 0)
+ this->skip_components = 3;
+ else if (strcmp(input, "gl_SkipComponents4") == 0)
+ this->skip_components = 4;
+
+ if (this->skip_components)
+ return true;
+ }
+
+ /* Parse a declaration. */
const char *bracket = strrchr(input, '[');
if (bracket) {
@@ -1581,6 +1625,8 @@ tfeedback_decl::init(struct gl_context *ctx, struct gl_shader_program *prog,
bool
tfeedback_decl::is_same(const tfeedback_decl &x, const tfeedback_decl &y)
{
+ assert(x.is_varying() && y.is_varying());
+
if (strcmp(x.var_name, y.var_name) != 0)
return false;
if (x.is_subscripted != y.is_subscripted)
@@ -1603,6 +1649,8 @@ tfeedback_decl::assign_location(struct gl_context *ctx,
struct gl_shader_program *prog,
ir_variable *output_var)
{
+ assert(this->is_varying());
+
if (output_var->type->is_array()) {
/* Array variable */
const unsigned matrix_cols =
@@ -1677,6 +1725,10 @@ bool
tfeedback_decl::accumulate_num_outputs(struct gl_shader_program *prog,
unsigned *count)
{
+ if (!this->is_varying()) {
+ return true;
+ }
+
if (!this->is_assigned()) {
/* From GL_EXT_transform_feedback:
* A program will fail to link if:
@@ -1709,9 +1761,16 @@ tfeedback_decl::accumulate_num_outputs(struct gl_shader_program *prog,
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
+ unsigned buffer, const unsigned max_outputs) const
{
+ assert(!this->next_buffer_separator);
+
+ /* Handle gl_SkipComponents. */
+ if (this->skip_components) {
+ info->BufferStride[buffer] += this->skip_components;
+ return true;
+ }
+
/* From GL_EXT_transform_feedback:
* A program will fail to link if:
*
@@ -1757,9 +1816,9 @@ tfeedback_decl::store(struct gl_context *ctx, struct gl_shader_program *prog,
}
assert(components_so_far == this->num_components());
- info->Varyings[varying].Name = ralloc_strdup(prog, this->orig_name);
- info->Varyings[varying].Type = this->type;
- info->Varyings[varying].Size = this->size;
+ info->Varyings[info->NumVarying].Name = ralloc_strdup(prog, this->orig_name);
+ info->Varyings[info->NumVarying].Type = this->type;
+ info->Varyings[info->NumVarying].Size = this->size;
info->NumVarying++;
return true;
@@ -1781,6 +1840,10 @@ parse_tfeedback_decls(struct gl_context *ctx, struct gl_shader_program *prog,
for (unsigned i = 0; i < num_names; ++i) {
if (!decls[i].init(ctx, prog, mem_ctx, varying_names[i]))
return false;
+
+ if (!decls[i].is_varying())
+ continue;
+
/* From GL_EXT_transform_feedback:
* A program will fail to link if:
*
@@ -1792,6 +1855,9 @@ parse_tfeedback_decls(struct gl_context *ctx, struct gl_shader_program *prog,
* feedback of arrays would be useless otherwise.
*/
for (unsigned j = 0; j < i; ++j) {
+ if (!decls[j].is_varying())
+ continue;
+
if (tfeedback_decl::is_same(decls[i], decls[j])) {
linker_error(prog, "Transform feedback varying %s specified "
"more than once.", varying_names[i]);
@@ -1948,6 +2014,9 @@ assign_varying_locations(struct gl_context *ctx,
}
for (unsigned i = 0; i < num_tfeedback_decls; ++i) {
+ if (!tfeedback_decls[i].is_varying())
+ continue;
+
if (!tfeedback_decls[i].is_assigned() &&
tfeedback_decls[i].matches_var(output_var)) {
if (output_var->location == -1) {
@@ -2059,9 +2128,6 @@ store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *prog,
memset(&prog->LinkedTransformFeedback, 0,
sizeof(prog->LinkedTransformFeedback));
- prog->LinkedTransformFeedback.NumBuffers =
- separate_attribs_mode ? num_tfeedback_decls : 1;
-
prog->LinkedTransformFeedback.Varyings =
rzalloc_array(prog,
struct gl_transform_feedback_varying_info,
@@ -2077,14 +2143,37 @@ store_tfeedback_info(struct gl_context *ctx, struct gl_shader_program *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, num_outputs))
- return false;
+ unsigned num_buffers = 0;
+
+ if (separate_attribs_mode) {
+ /* GL_SEPARATE_ATTRIBS */
+ for (unsigned i = 0; i < num_tfeedback_decls; ++i) {
+ if (!tfeedback_decls[i].store(ctx, prog, &prog->LinkedTransformFeedback,
+ num_buffers, num_outputs))
+ return false;
+
+ num_buffers++;
+ }
+ }
+ else {
+ /* GL_INVERLEAVED_ATTRIBS */
+ for (unsigned i = 0; i < num_tfeedback_decls; ++i) {
+ if (tfeedback_decls[i].is_next_buffer_separator()) {
+ num_buffers++;
+ continue;
+ }
+
+ if (!tfeedback_decls[i].store(ctx, prog,
+ &prog->LinkedTransformFeedback,
+ num_buffers, num_outputs))
+ return false;
+ }
+ num_buffers++;
}
+
assert(prog->LinkedTransformFeedback.NumOutputs == num_outputs);
+ prog->LinkedTransformFeedback.NumBuffers = num_buffers;
return true;
}