glsl: implement ARB_transform_feedback3 in the linker

Acked-by: Ian Romanick <ian.d.romanick@intel.com>
This commit is contained in:
Marek Olšák 2011-12-18 02:39:34 +01:00
parent 9576d555e0
commit 21cb5ed20d
3 changed files with 106 additions and 15 deletions

View file

@ -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;
}

View file

@ -141,6 +141,7 @@ static const struct extension extension_table[] = {
{ "GL_ARB_texture_swizzle", o(EXT_texture_swizzle), GL, 2008 },
{ "GL_ARB_timer_query", o(ARB_timer_query), GL, 2010 },
{ "GL_ARB_transform_feedback2", o(ARB_transform_feedback2), GL, 2010 },
{ "GL_ARB_transform_feedback3", o(ARB_transform_feedback3), GL, 2010 },
{ "GL_ARB_transpose_matrix", o(ARB_transpose_matrix), GL, 1999 },
{ "GL_ARB_uniform_buffer_object", o(ARB_uniform_buffer_object), GL, 2009 },
{ "GL_ARB_vertex_array_bgra", o(EXT_vertex_array_bgra), GL, 2008 },

View file

@ -2937,6 +2937,7 @@ struct gl_extensions
GLboolean ARB_texture_storage;
GLboolean ARB_timer_query;
GLboolean ARB_transform_feedback2;
GLboolean ARB_transform_feedback3;
GLboolean ARB_transpose_matrix;
GLboolean ARB_uniform_buffer_object;
GLboolean ARB_vertex_array_object;