From: Fabian Bieler <fabianbie...@fastmail.fm> --- src/glsl/ast.h | 1 + src/glsl/ast_to_hir.cpp | 48 +++++++++++++++++--- src/glsl/ast_type.cpp | 3 +- src/glsl/builtin_variables.cpp | 18 +++++--- src/glsl/glsl_lexer.ll | 3 +- src/glsl/glsl_parser.yy | 15 ++++--- src/glsl/glsl_parser_extras.cpp | 2 + src/glsl/glsl_types.cpp | 5 +++ src/glsl/glsl_types.h | 6 +++ src/glsl/ir.cpp | 2 + src/glsl/ir.h | 1 + src/glsl/ir_print_visitor.cpp | 5 ++- src/glsl/ir_reader.cpp | 2 + src/glsl/ir_set_program_inouts.cpp | 75 +++++++++++++++++++++++++++++-- src/glsl/link_varyings.cpp | 15 ++++++- src/glsl/lower_named_interface_blocks.cpp | 1 + src/glsl/lower_packed_varyings.cpp | 1 + 17 files changed, 176 insertions(+), 27 deletions(-)
diff --git a/src/glsl/ast.h b/src/glsl/ast.h index a74f35d..3261268 100644 --- a/src/glsl/ast.h +++ b/src/glsl/ast.h @@ -432,6 +432,7 @@ struct ast_type_qualifier { unsigned out:1; unsigned centroid:1; unsigned sample:1; + unsigned patch:1; unsigned uniform:1; unsigned smooth:1; unsigned flat:1; diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp index 0d93b48..2490990 100644 --- a/src/glsl/ast_to_hir.cpp +++ b/src/glsl/ast_to_hir.cpp @@ -2473,6 +2473,9 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, var->data.stream = qual->stream; } + if (qual->flags.q.patch) + var->data.patch = 1; + if (qual->flags.q.attribute && state->stage != MESA_SHADER_VERTEX) { var->type = glsl_type::error_type; _mesa_glsl_error(loc, state, @@ -3114,14 +3117,17 @@ handle_tess_ctrl_shader_output_decl(struct _mesa_glsl_parse_state *state, num_vertices = state->out_qualifier->vertices; } - /* This function should only be called for arrays. */ - if (!var->type->is_array()) { - assert(state->error); + if (!var->type->is_array() && !var->data.patch) { + _mesa_glsl_error(&loc, state, + "tessellation control shader outputs must be arrays"); /* To avoid cascading failures, short circuit the checks below. */ return; } + if (var->data.patch) + return; + if (var->type->is_unsized_array()) { if (num_vertices != 0) var->type = glsl_type::get_array_instance(var->type->fields.array, @@ -3678,10 +3684,7 @@ ast_declarator_list::hir(exec_list *instructions, } } else if (var->data.mode == ir_var_shader_out) { if (state->stage == MESA_SHADER_TESS_CTRL) { - // XXX: only allow non-arrays with patch-out attribute - if (var->type->is_array()) { - handle_tess_ctrl_shader_output_decl(state, loc, var); - } + handle_tess_ctrl_shader_output_decl(state, loc, var); } } @@ -3797,6 +3800,33 @@ ast_declarator_list::hir(exec_list *instructions, } + /* From section 4.3.4 of the GLSL 4.00 spec: + * "Input variables may not be declared using the patch in qualifier + * in tessellation control or geometry shaders." + * + * From section 4.3.6 of the GLSL 4.00 spec: + * "It is an error to use patch out in a vertex, tessellation + * evaluation, or geometry shader." + * + * This doesn't explicitly forbid using them in a fragment shader, but + * that's probably just an oversight. + */ + if (state->stage != MESA_SHADER_TESS_EVAL + && this->type->qualifier.flags.q.patch + && this->type->qualifier.flags.q.in) { + + _mesa_glsl_error(&loc, state, "'patch in' can only be used in a " + "tessellation evaluation shader"); + } + + if (state->stage != MESA_SHADER_TESS_CTRL + && this->type->qualifier.flags.q.patch + && this->type->qualifier.flags.q.out) { + + _mesa_glsl_error(&loc, state, "'patch out' can only be used in a " + "tessellation control shader"); + } + /* Precision qualifiers exists only in GLSL versions 1.00 and >= 1.30. */ if (this->type->qualifier.precision != ast_precision_none) { @@ -5267,6 +5297,7 @@ ast_process_structure_or_interface_block(exec_list *instructions, interpret_interpolation_qualifier(qual, var_mode, state, &loc); fields[i].centroid = qual->flags.q.centroid ? 1 : 0; fields[i].sample = qual->flags.q.sample ? 1 : 0; + fields[i].patch = qual->flags.q.patch ? 1 : 0; /* Only save explicitly defined streams in block's field */ fields[i].stream = qual->flags.q.explicit_stream ? qual->stream : -1; @@ -5576,6 +5607,8 @@ ast_interface_block::hir(exec_list *instructions, earlier_per_vertex->fields.structure[j].centroid; fields[i].sample = earlier_per_vertex->fields.structure[j].sample; + fields[i].patch = + earlier_per_vertex->fields.structure[j].patch; } } @@ -5741,6 +5774,7 @@ ast_interface_block::hir(exec_list *instructions, var->data.interpolation = fields[i].interpolation; var->data.centroid = fields[i].centroid; var->data.sample = fields[i].sample; + var->data.patch = fields[i].patch; var->init_interface_type(block_type); if (fields[i].matrix_layout == GLSL_MATRIX_LAYOUT_INHERITED) { diff --git a/src/glsl/ast_type.cpp b/src/glsl/ast_type.cpp index 69175eb..4c7b3fc 100644 --- a/src/glsl/ast_type.cpp +++ b/src/glsl/ast_type.cpp @@ -85,7 +85,8 @@ bool ast_type_qualifier::has_auxiliary_storage() const { return this->flags.q.centroid - || this->flags.q.sample; + || this->flags.q.sample + || this->flags.q.patch; } const char* diff --git a/src/glsl/builtin_variables.cpp b/src/glsl/builtin_variables.cpp index 7ba0fe8..97ef68c 100644 --- a/src/glsl/builtin_variables.cpp +++ b/src/glsl/builtin_variables.cpp @@ -853,10 +853,13 @@ builtin_variable_generator::generate_tcs_special_vars() add_input(VARYING_SLOT_PRIMITIVE_ID, int_t, "gl_PrimitiveID");// XXX: or sysval? add_system_value(SYSTEM_VALUE_INVOCATION_ID, int_t, "gl_InvocationID"); - add_output(VARYING_SLOT_TESS_LEVEL_OUTER, + ir_variable *var; + var = add_output(VARYING_SLOT_TESS_LEVEL_OUTER, array(float_t, 4), "gl_TessLevelOuter"); - add_output(VARYING_SLOT_TESS_LEVEL_INNER, + var->data.patch = 1; + var = add_output(VARYING_SLOT_TESS_LEVEL_INNER, array(float_t, 2), "gl_TessLevelInner"); + var->data.patch = 1; } @@ -870,10 +873,13 @@ builtin_variable_generator::generate_tes_special_vars() add_input(VARYING_SLOT_PRIMITIVE_ID, int_t, "gl_PrimitiveID");// XXX: or sysval? add_system_value(SYSTEM_VALUE_TESS_COORD, vec3_t, "gl_TessCoord"); - add_input(VARYING_SLOT_TESS_LEVEL_OUTER, - array(float_t, 4), "gl_TessLevelOuter"); - add_input(VARYING_SLOT_TESS_LEVEL_INNER, - array(float_t, 2), "gl_TessLevelInner"); + ir_variable *var; + var = add_input(VARYING_SLOT_TESS_LEVEL_OUTER, + array(float_t, 4), "gl_TessLevelOuter"); + var->data.patch = 1; + var = add_input(VARYING_SLOT_TESS_LEVEL_INNER, + array(float_t, 2), "gl_TessLevelInner"); + var->data.patch = 1; } diff --git a/src/glsl/glsl_lexer.ll b/src/glsl/glsl_lexer.ll index b7c4aad..2229161 100644 --- a/src/glsl/glsl_lexer.ll +++ b/src/glsl/glsl_lexer.ll @@ -296,6 +296,8 @@ invariant KEYWORD(120, 100, 120, 100, INVARIANT); flat KEYWORD(130, 100, 130, 300, FLAT); smooth KEYWORD(130, 300, 130, 300, SMOOTH); noperspective KEYWORD(130, 300, 130, 0, NOPERSPECTIVE); +noperspective KEYWORD(130, 300, 130, 0, NOPERSPECTIVE); +patch KEYWORD_WITH_ALT(0, 300, 400, 0, yyextra->ARB_tessellation_shader_enable, PATCH); sampler1D DEPRECATED_ES_KEYWORD(SAMPLER1D); sampler2D return SAMPLER2D; @@ -546,7 +548,6 @@ usamplerBuffer KEYWORD(140, 300, 140, 0, USAMPLERBUFFER); /* Additional reserved words in GLSL ES 3.00 */ resource KEYWORD(0, 300, 0, 0, RESOURCE); -patch KEYWORD(0, 300, 0, 0, PATCH); sample KEYWORD_WITH_ALT(400, 300, 400, 0, yyextra->ARB_gpu_shader5_enable, SAMPLE); subroutine KEYWORD(0, 300, 0, 0, SUBROUTINE); diff --git a/src/glsl/glsl_parser.yy b/src/glsl/glsl_parser.yy index d3cfb97..dbab815 100644 --- a/src/glsl/glsl_parser.yy +++ b/src/glsl/glsl_parser.yy @@ -131,8 +131,9 @@ static bool match_layout_qualifier(const char *s1, const char *s2, %token ATTRIBUTE CONST_TOK BOOL_TOK FLOAT_TOK INT_TOK UINT_TOK %token BREAK CONTINUE DO ELSE FOR IF DISCARD RETURN SWITCH CASE DEFAULT %token BVEC2 BVEC3 BVEC4 IVEC2 IVEC3 IVEC4 UVEC2 UVEC3 UVEC4 VEC2 VEC3 VEC4 -%token CENTROID IN_TOK OUT_TOK INOUT_TOK UNIFORM VARYING SAMPLE +%token CENTROID IN_TOK OUT_TOK INOUT_TOK UNIFORM VARYING PATCH SAMPLE %token NOPERSPECTIVE FLAT SMOOTH +%token ROW_MAJOR PACKED_TOK %token MAT2X2 MAT2X3 MAT2X4 %token MAT3X2 MAT3X3 MAT3X4 %token MAT4X2 MAT4X3 MAT4X4 @@ -180,18 +181,18 @@ static bool match_layout_qualifier(const char *s1, const char *s2, /* Reserved words that are not actually used in the grammar. */ -%token ASM CLASS UNION ENUM TYPEDEF TEMPLATE THIS PACKED_TOK GOTO +%token ASM CLASS UNION ENUM TYPEDEF TEMPLATE THIS GOTO %token INLINE_TOK NOINLINE PUBLIC_TOK STATIC EXTERN EXTERNAL %token LONG_TOK SHORT_TOK DOUBLE_TOK HALF FIXED_TOK UNSIGNED INPUT_TOK %token HVEC2 HVEC3 HVEC4 DVEC2 DVEC3 DVEC4 FVEC2 FVEC3 FVEC4 %token SAMPLER3DRECT %token SIZEOF CAST NAMESPACE USING -%token RESOURCE PATCH +%token RESOURCE %token SUBROUTINE %token ERROR_TOK -%token COMMON PARTITION ACTIVE FILTER ROW_MAJOR +%token COMMON PARTITION ACTIVE FILTER %type <identifier> variable_identifier %type <node> statement @@ -1796,7 +1797,11 @@ auxiliary_storage_qualifier: memset(& $$, 0, sizeof($$)); $$.flags.q.sample = 1; } - /* TODO: "patch" also goes here someday. */ + | PATCH + { + memset(& $$, 0, sizeof($$)); + $$.flags.q.patch = 1; + } storage_qualifier: CONST_TOK diff --git a/src/glsl/glsl_parser_extras.cpp b/src/glsl/glsl_parser_extras.cpp index 357e3b1..0b45f44 100644 --- a/src/glsl/glsl_parser_extras.cpp +++ b/src/glsl/glsl_parser_extras.cpp @@ -814,6 +814,8 @@ _mesa_ast_type_qualifier_print(const struct ast_type_qualifier *q) printf("centroid "); if (q->flags.q.sample) printf("sample "); + if (q->flags.q.patch) + printf("patch "); if (q->flags.q.uniform) printf("uniform "); if (q->flags.q.smooth) diff --git a/src/glsl/glsl_types.cpp b/src/glsl/glsl_types.cpp index 66e9b13..1ed3a24 100644 --- a/src/glsl/glsl_types.cpp +++ b/src/glsl/glsl_types.cpp @@ -109,6 +109,7 @@ glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields, this->fields.structure[i].centroid = fields[i].centroid; this->fields.structure[i].sample = fields[i].sample; this->fields.structure[i].matrix_layout = fields[i].matrix_layout; + this->fields.structure[i].patch = fields[i].patch; } } @@ -137,6 +138,7 @@ glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields, this->fields.structure[i].centroid = fields[i].centroid; this->fields.structure[i].sample = fields[i].sample; this->fields.structure[i].matrix_layout = fields[i].matrix_layout; + this->fields.structure[i].patch = fields[i].patch; } } @@ -511,6 +513,9 @@ glsl_type::record_compare(const glsl_type *b) const if (this->fields.structure[i].sample != b->fields.structure[i].sample) return false; + if (this->fields.structure[i].patch + != b->fields.structure[i].patch) + return false; } return true; diff --git a/src/glsl/glsl_types.h b/src/glsl/glsl_types.h index d545533..0fe9f5f 100644 --- a/src/glsl/glsl_types.h +++ b/src/glsl/glsl_types.h @@ -710,6 +710,12 @@ struct glsl_struct_field { unsigned matrix_layout:2; /** + * For interface blocks, 1 if this variable is a per-patch input or output + * (as in ir_variable::patch). 0 otherwise. + */ + unsigned patch:1; + + /** * For interface blocks, it has a value if this variable uses multiple vertex * streams (as in ir_variable::stream). -1 otherwise. */ diff --git a/src/glsl/ir.cpp b/src/glsl/ir.cpp index 739a9f4..e3b200c 100644 --- a/src/glsl/ir.cpp +++ b/src/glsl/ir.cpp @@ -1564,6 +1564,7 @@ ir_variable::ir_variable(const struct glsl_type *type, const char *name, this->data.read_only = false; this->data.centroid = false; this->data.sample = false; + this->data.patch = false; this->data.invariant = false; this->data.how_declared = ir_var_declared_normally; this->data.mode = mode; @@ -1680,6 +1681,7 @@ ir_function_signature::qualifiers_match(exec_list *params) a->data.interpolation != b->data.interpolation || a->data.centroid != b->data.centroid || a->data.sample != b->data.sample || + a->data.patch != b->data.patch || a->data.image_read_only != b->data.image_read_only || a->data.image_write_only != b->data.image_write_only || a->data.image_coherent != b->data.image_coherent || diff --git a/src/glsl/ir.h b/src/glsl/ir.h index 8003f88..94c330a 100644 --- a/src/glsl/ir.h +++ b/src/glsl/ir.h @@ -560,6 +560,7 @@ public: unsigned read_only:1; unsigned centroid:1; unsigned sample:1; + unsigned patch:1; unsigned invariant:1; unsigned precise:1; diff --git a/src/glsl/ir_print_visitor.cpp b/src/glsl/ir_print_visitor.cpp index bd39805..1cf28ea 100644 --- a/src/glsl/ir_print_visitor.cpp +++ b/src/glsl/ir_print_visitor.cpp @@ -163,6 +163,7 @@ void ir_print_visitor::visit(ir_variable *ir) const char *const cent = (ir->data.centroid) ? "centroid " : ""; const char *const samp = (ir->data.sample) ? "sample " : ""; + const char *const patc = (ir->data.patch) ? "patch " : ""; const char *const inv = (ir->data.invariant) ? "invariant " : ""; const char *const mode[] = { "", "uniform ", "shader_in ", "shader_out ", "in ", "out ", "inout ", @@ -172,8 +173,8 @@ void ir_print_visitor::visit(ir_variable *ir) const char *const interp[] = { "", "smooth", "flat", "noperspective" }; STATIC_ASSERT(ARRAY_SIZE(interp) == INTERP_QUALIFIER_COUNT); - fprintf(f, "(%s%s%s%s%s%s) ", - cent, samp, inv, mode[ir->data.mode], + fprintf(f, "(%s%s%s%s%s%s%s) ", + cent, samp, patc, inv, mode[ir->data.mode], stream[ir->data.stream], interp[ir->data.interpolation]); diff --git a/src/glsl/ir_reader.cpp b/src/glsl/ir_reader.cpp index ae00e79..456dd4f 100644 --- a/src/glsl/ir_reader.cpp +++ b/src/glsl/ir_reader.cpp @@ -414,6 +414,8 @@ ir_reader::read_declaration(s_expression *expr) var->data.centroid = 1; } else if (strcmp(qualifier->value(), "sample") == 0) { var->data.sample = 1; + } else if (strcmp(qualifier->value(), "patch") == 0) { + var->data.patch = 1; } else if (strcmp(qualifier->value(), "invariant") == 0) { var->data.invariant = 1; } else if (strcmp(qualifier->value(), "uniform") == 0) { diff --git a/src/glsl/ir_set_program_inouts.cpp b/src/glsl/ir_set_program_inouts.cpp index 97ead75..ff15362 100644 --- a/src/glsl/ir_set_program_inouts.cpp +++ b/src/glsl/ir_set_program_inouts.cpp @@ -130,6 +130,24 @@ ir_set_program_inouts_visitor::mark_whole_variable(ir_variable *var) type = type->fields.array; } + if (this->shader_stage == MESA_SHADER_TESS_CTRL && + var->data.mode == ir_var_shader_in && type->is_array()) { + type = type->fields.array; + } + + if (this->shader_stage == MESA_SHADER_TESS_CTRL && + var->data.mode == ir_var_shader_out && !var->data.patch) { + assert(type->is_array()); + type = type->fields.array; + } + + if (this->shader_stage == MESA_SHADER_TESS_EVAL && + var->data.mode == ir_var_shader_in && + type->is_array() && !var->data.patch) { + assert(type->is_array()); + type = type->fields.array; + } + mark(this->prog, var, 0, type->count_attribute_slots(), this->shader_stage == MESA_SHADER_FRAGMENT); } @@ -155,6 +173,9 @@ ir_set_program_inouts_visitor::visit(ir_dereference_variable *ir) * * *Except gl_PrimitiveIDIn, as noted below. * + * For tessellation control shaders all inputs and non-patch outputs are + * arrays. For tessellation evaluation shaders non-patch inputs are arrays. + * * If the index can't be interpreted as a constant, or some other problem * occurs, then nothing will be marked and false will be returned. */ @@ -174,6 +195,36 @@ ir_set_program_inouts_visitor::try_mark_partial_variable(ir_variable *var, type = type->fields.array; } + if (this->shader_stage == MESA_SHADER_TESS_CTRL && + var->data.mode == ir_var_shader_in) { + /* The only tessellation control shader inputs that are not arrays are + * gl_PatchVerticesIn, gl_PrimitiveID and gl_InvocationID. + * These can't be indexed so for them this code should never be reached. + */ + assert(type->is_array()); + type = type->fields.array; + } + + if (this->shader_stage == MESA_SHADER_TESS_CTRL && + var->data.mode == ir_var_shader_out && !var->data.patch) { + /* XXX: User defined outputs could be patch non-array but indexable, + * e.g.: patch out mat4 foo; + * what to do? + */ + assert(type->is_array()); + type = type->fields.array; + } + + if (this->shader_stage == MESA_SHADER_TESS_EVAL && + var->data.mode == ir_var_shader_in && !var->data.patch) { + /* XXX: User defined inputs could be patch non-array but indexable, + * e.g.: patch in mat4 bar; + * what to do? + */ + assert(type->is_array()); + type = type->fields.array; + } + /* The code below only handles: * * - Indexing into matrices @@ -246,8 +297,16 @@ ir_set_program_inouts_visitor::visit_enter(ir_dereference_array *ir) */ if (ir_dereference_variable * const deref_var = inner_array->array->as_dereference_variable()) { - if (this->shader_stage == MESA_SHADER_GEOMETRY && - deref_var->var->data.mode == ir_var_shader_in) { + if ((this->shader_stage == MESA_SHADER_GEOMETRY && + deref_var->var->data.mode == ir_var_shader_in) || + (this->shader_stage == MESA_SHADER_TESS_CTRL && + deref_var->var->data.mode == ir_var_shader_in) || + (this->shader_stage == MESA_SHADER_TESS_CTRL && + deref_var->var->data.mode == ir_var_shader_out && + !deref_var->var->data.patch) || + (this->shader_stage == MESA_SHADER_TESS_EVAL && + deref_var->var->data.mode == ir_var_shader_in && + !deref_var->var->data.patch)) { /* foo is a geometry shader input, so i is the vertex, and j the * part of the input we're accessing. */ @@ -265,8 +324,16 @@ ir_set_program_inouts_visitor::visit_enter(ir_dereference_array *ir) } else if (ir_dereference_variable * const deref_var = ir->array->as_dereference_variable()) { /* ir => foo[i], where foo is a variable. */ - if (this->shader_stage == MESA_SHADER_GEOMETRY && - deref_var->var->data.mode == ir_var_shader_in) { + if ((this->shader_stage == MESA_SHADER_GEOMETRY && + deref_var->var->data.mode == ir_var_shader_in) || + (this->shader_stage == MESA_SHADER_TESS_CTRL && + deref_var->var->data.mode == ir_var_shader_in) || + (this->shader_stage == MESA_SHADER_TESS_CTRL && + deref_var->var->data.mode == ir_var_shader_out && + !deref_var->var->data.patch) || + (this->shader_stage == MESA_SHADER_TESS_EVAL && + deref_var->var->data.mode == ir_var_shader_in && + !deref_var->var->data.patch)) { /* foo is a geometry shader input, so i is the vertex, and we're * accessing the entire input. */ diff --git a/src/glsl/link_varyings.cpp b/src/glsl/link_varyings.cpp index ee54666..53c26d2 100644 --- a/src/glsl/link_varyings.cpp +++ b/src/glsl/link_varyings.cpp @@ -116,6 +116,18 @@ cross_validate_types_and_qualifiers(struct gl_shader_program *prog, return; } + if (input->data.patch != output->data.patch) { + linker_error(prog, + "%s shader output `%s' %s patch qualifier, " + "but %s shader input %s patch qualifier\n", + _mesa_shader_stage_to_string(producer_stage), + output->name, + (output->data.patch) ? "has" : "lacks", + _mesa_shader_stage_to_string(consumer_stage), + (input->data.patch) ? "has" : "lacks"); + return; + } + if (input->data.invariant != output->data.invariant) { linker_error(prog, "%s shader output `%s' %s invariant qualifier, " @@ -991,7 +1003,8 @@ varying_matches::compute_packing_class(const ir_variable *var) * * Therefore, the packing class depends only on the interpolation type. */ - unsigned packing_class = var->data.centroid | (var->data.sample << 1); + unsigned packing_class = var->data.centroid | (var->data.sample << 1) | + (var->data.patch << 2); packing_class *= 4; packing_class += var->data.interpolation; return packing_class; diff --git a/src/glsl/lower_named_interface_blocks.cpp b/src/glsl/lower_named_interface_blocks.cpp index 7304c51..2f1e3af 100644 --- a/src/glsl/lower_named_interface_blocks.cpp +++ b/src/glsl/lower_named_interface_blocks.cpp @@ -158,6 +158,7 @@ flatten_named_interface_blocks_declarations::run(exec_list *instructions) iface_t->fields.structure[i].interpolation; new_var->data.centroid = iface_t->fields.structure[i].centroid; new_var->data.sample = iface_t->fields.structure[i].sample; + new_var->data.patch = iface_t->fields.structure[i].patch; new_var->init_interface_type(iface_t); hash_table_insert(interface_namespace, new_var, diff --git a/src/glsl/lower_packed_varyings.cpp b/src/glsl/lower_packed_varyings.cpp index 7801483..0c8696d 100644 --- a/src/glsl/lower_packed_varyings.cpp +++ b/src/glsl/lower_packed_varyings.cpp @@ -555,6 +555,7 @@ lower_packed_varyings_visitor::get_packed_varying_deref( } packed_var->data.centroid = unpacked_var->data.centroid; packed_var->data.sample = unpacked_var->data.sample; + packed_var->data.patch = unpacked_var->data.patch; packed_var->data.interpolation = unpacked_var->data.interpolation; packed_var->data.location = location; unpacked_var->insert_before(packed_var); -- 2.1.0 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev