From: Paul Berry Date: Wed, 19 Dec 2012 00:37:52 +0000 (-0800) Subject: glsl: Pack flat "varyings" of mixed types together. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=c35abcd1b0d0e0059c60781bd21558872020553d;p=mesa.git glsl: Pack flat "varyings" of mixed types together. This patch enhances the varying packing code so that flat varyings of uint, int, and float types can be packed together. We accomplish this in lower_packed_varyings.cpp by making the type of all flat varyings ivec4, and then using information-preserving type conversions (e.g. ir_unop_bitcast_f2i) to convert all other types to ints. The varying_matches::compute_packing_class() function is updated to reflect the fact that varying packing no longer needs to segregate varyings of different base types. Fixes piglit test varying-packing-mixed-types. Reviewed-by: Kenneth Graunke v2: Split lower_packed_varyings_visitor::bitwise_assign into pack/unpack variants. --- diff --git a/src/glsl/link_varyings.cpp b/src/glsl/link_varyings.cpp index b9c3f5d434d..5c27f231e72 100644 --- a/src/glsl/link_varyings.cpp +++ b/src/glsl/link_varyings.cpp @@ -777,17 +777,25 @@ varying_matches::store_locations(unsigned producer_base, unsigned varying_matches::compute_packing_class(ir_variable *var) { - /* In this initial implementation we conservatively assume that variables - * can only be packed if their base type (float/int/uint/bool) matches and - * their interpolation and centroid qualifiers match. + /* Without help from the back-end, there is no way to pack together + * variables with different interpolation types, because + * lower_packed_varyings must choose exactly one interpolation type for + * each packed varying it creates. * - * TODO: relax these restrictions when the driver back-end permits. + * However, we can safely pack together floats, ints, and uints, because: + * + * - varyings of base type "int" and "uint" must use the "flat" + * interpolation type, which can only occur in GLSL 1.30 and above. + * + * - On platforms that support GLSL 1.30 and above, lower_packed_varyings + * can store flat floats as ints without losing any information (using + * the ir_unop_bitcast_* opcodes). + * + * Therefore, the packing class depends only on the interpolation type. */ unsigned packing_class = var->centroid ? 1 : 0; packing_class *= 4; packing_class += var->interpolation; - packing_class *= GLSL_TYPE_ERROR; - packing_class += var->type->get_scalar_type()->base_type; return packing_class; } diff --git a/src/glsl/lower_packed_varyings.cpp b/src/glsl/lower_packed_varyings.cpp index 09c551c4e63..9e7f274b7d1 100644 --- a/src/glsl/lower_packed_varyings.cpp +++ b/src/glsl/lower_packed_varyings.cpp @@ -66,6 +66,10 @@ * performance. However, hopefully in most cases the performance loss will * either be absorbed by a later optimization pass, or it will be offset by * memory bandwidth savings (because fewer varyings are used). + * + * This lowering pass also packs flat floats, ints, and uints together, by + * using ivec4 as the base type of flat "varyings", and using appropriate + * casts to convert floats and uints into ints. */ #include "glsl_symbol_table.h" @@ -90,6 +94,8 @@ public: void run(exec_list *instructions); private: + ir_assignment *bitwise_assign_pack(ir_rvalue *lhs, ir_rvalue *rhs); + ir_assignment *bitwise_assign_unpack(ir_rvalue *lhs, ir_rvalue *rhs); unsigned lower_rvalue(ir_rvalue *rvalue, unsigned fine_location, ir_variable *unpacked_var, const char *name); unsigned lower_arraylike(ir_rvalue *rvalue, unsigned array_size, @@ -181,6 +187,75 @@ lower_packed_varyings_visitor::run(exec_list *instructions) } } + +/** + * Make an ir_assignment from \c rhs to \c lhs, performing appropriate + * bitcasts if necessary to match up types. + * + * This function is called when packing varyings. + */ +ir_assignment * +lower_packed_varyings_visitor::bitwise_assign_pack(ir_rvalue *lhs, + ir_rvalue *rhs) +{ + if (lhs->type->base_type != rhs->type->base_type) { + /* Since we only mix types in flat varyings, and we always store flat + * varyings as type ivec4, we need only produce conversions from (uint + * or float) to int. + */ + assert(lhs->type->base_type == GLSL_TYPE_INT); + switch (rhs->type->base_type) { + case GLSL_TYPE_UINT: + rhs = new(this->mem_ctx) + ir_expression(ir_unop_u2i, lhs->type, rhs); + break; + case GLSL_TYPE_FLOAT: + rhs = new(this->mem_ctx) + ir_expression(ir_unop_bitcast_f2i, lhs->type, rhs); + break; + default: + assert(!"Unexpected type conversion while lowering varyings"); + break; + } + } + return new(this->mem_ctx) ir_assignment(lhs, rhs); +} + + +/** + * Make an ir_assignment from \c rhs to \c lhs, performing appropriate + * bitcasts if necessary to match up types. + * + * This function is called when unpacking varyings. + */ +ir_assignment * +lower_packed_varyings_visitor::bitwise_assign_unpack(ir_rvalue *lhs, + ir_rvalue *rhs) +{ + if (lhs->type->base_type != rhs->type->base_type) { + /* Since we only mix types in flat varyings, and we always store flat + * varyings as type ivec4, we need only produce conversions from int to + * (uint or float). + */ + assert(rhs->type->base_type == GLSL_TYPE_INT); + switch (lhs->type->base_type) { + case GLSL_TYPE_UINT: + rhs = new(this->mem_ctx) + ir_expression(ir_unop_i2u, lhs->type, rhs); + break; + case GLSL_TYPE_FLOAT: + rhs = new(this->mem_ctx) + ir_expression(ir_unop_bitcast_i2f, lhs->type, rhs); + break; + default: + assert(!"Unexpected type conversion while lowering varyings"); + break; + } + } + return new(this->mem_ctx) ir_assignment(lhs, rhs); +} + + /** * Recursively pack or unpack the given varying (or portion of a varying) by * traversing all of its constituent vectors. @@ -262,12 +337,12 @@ lower_packed_varyings_visitor::lower_rvalue(ir_rvalue *rvalue, ir_swizzle *swizzle = new(this->mem_ctx) ir_swizzle(packed_deref, swizzle_values, components); if (this->mode == ir_var_out) { - ir_assignment *assignment = new(this->mem_ctx) - ir_assignment(swizzle, rvalue); + ir_assignment *assignment + = this->bitwise_assign_pack(swizzle, rvalue); this->main_instructions->push_tail(assignment); } else { - ir_assignment *assignment = new(this->mem_ctx) - ir_assignment(rvalue, swizzle); + ir_assignment *assignment + = this->bitwise_assign_unpack(rvalue, swizzle); this->main_instructions->push_head(assignment); } return fine_location + components; @@ -306,8 +381,9 @@ lower_packed_varyings_visitor::lower_arraylike(ir_rvalue *rvalue, * If no packed varying has been created for the given varying location yet, * create it and add it to the shader before returning it. * - * The newly created varying inherits its base type (float, uint, or int) and - * interpolation parameters from \c unpacked_var. + * The newly created varying inherits its interpolation parameters from \c + * unpacked_var. Its base type is ivec4 if we are lowering a flat varying, + * vec4 otherwise. */ ir_variable * lower_packed_varyings_visitor::get_packed_varying(unsigned location, @@ -318,8 +394,11 @@ lower_packed_varyings_visitor::get_packed_varying(unsigned location, assert(slot < locations_used); if (this->packed_varyings[slot] == NULL) { char *packed_name = ralloc_asprintf(this->mem_ctx, "packed:%s", name); - const glsl_type *packed_type = glsl_type::get_instance( - unpacked_var->type->get_scalar_type()->base_type, 4, 1); + const glsl_type *packed_type; + if (unpacked_var->interpolation == INTERP_QUALIFIER_FLAT) + packed_type = glsl_type::ivec4_type; + else + packed_type = glsl_type::vec4_type; ir_variable *packed_var = new(this->mem_ctx) ir_variable(packed_type, packed_name, this->mode); packed_var->centroid = unpacked_var->centroid;