diff options
author | Danylo Piliaiev <danylo.piliaiev@globallogic.com> | 2019-10-10 19:11:00 +0300 |
---|---|---|
committer | Marge Bot <eric+marge@anholt.net> | 2021-04-01 17:16:33 +0000 |
commit | 67e33db4a6c302f09ba74a534aa4b18815239aa1 (patch) | |
tree | 67c59c98b3d335738e20902dbebdc2bdd30e95ea /src/compiler | |
parent | c432cb672a1f409a88e1b85d4405426103ff023b (diff) |
glsl/linker: Fix xfb with explicit locations and 64bit types
1) Per GL_ARB_enhanced_layouts if explicit location is set for varying,
each struct member, array element and matrix row will take
separate location. With GL_ARB_gpu_shader_fp64/GL_ARB_gpu_shader_int64
they may take two locations.
Examples:
| layout(location=0) dvec3[2] a; | layout(location=4) vec2[4] b; |
| | |
| 32b 32b 32b 32b | 32b 32b 32b 32b |
| 0 X X Y Y | 4 X Y 0 0 |
| 1 Z Z 0 0 | 5 X Y 0 0 |
| 2 X X Y Y | 6 X Y 0 0 |
| 3 Z Z 0 0 | 7 X Y 0 0 |
Previously it wasn't taken into account.
2) Captured double-precision variables should be aligned to
8 bytes per GL_ARB_gpu_shader_fp64:
"If any variable captured in transform feedback has double-precision
components, the practical requirements for defined behavior are:
...
(c) each double-precision variable captured must be aligned to a
multiple of eight bytes relative to the beginning of a vertex."
v2: fix `output_size` calculations
( Andrii Simiklit <andrii.simiklit@globallogic.com> )
Closes: https://gitlab.freedesktop.org/mesa/mesa/issues/1667
Reviewed-by: Tapani Pälli <tapani.palli@intel.com>
Signed-off-by: Danylo Piliaiev <danylo.piliaiev@globallogic.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/2333>
Diffstat (limited to 'src/compiler')
-rw-r--r-- | src/compiler/glsl/link_varyings.cpp | 114 | ||||
-rw-r--r-- | src/compiler/glsl/link_varyings.h | 12 |
2 files changed, 111 insertions, 15 deletions
diff --git a/src/compiler/glsl/link_varyings.cpp b/src/compiler/glsl/link_varyings.cpp index 0080c2451fb..2f59967339e 100644 --- a/src/compiler/glsl/link_varyings.cpp +++ b/src/compiler/glsl/link_varyings.cpp @@ -65,6 +65,13 @@ get_varying_type(const ir_variable *var, gl_shader_stage stage) return type; } +static bool +varying_has_user_specified_location(const ir_variable *var) +{ + return var->data.explicit_location && + var->data.location >= VARYING_SLOT_VAR0; +} + static void create_xfb_varying_names(void *mem_ctx, const glsl_type *t, char **name, size_t name_length, unsigned *count, @@ -1081,7 +1088,7 @@ tfeedback_decl::assign_location(struct gl_context *ctx, unsigned fine_location = this->matched_candidate->toplevel_var->data.location * 4 + this->matched_candidate->toplevel_var->data.location_frac - + this->matched_candidate->offset; + + this->matched_candidate->struct_offset_floats; const unsigned dmul = this->matched_candidate->type->without_array()->is_64bit() ? 2 : 1; @@ -1174,7 +1181,7 @@ tfeedback_decl::assign_location(struct gl_context *ctx, this->stream_id = this->matched_candidate->toplevel_var->data.stream; unsigned array_offset = this->array_subscript * 4 * dmul; - unsigned struct_offset = this->matched_candidate->offset * 4 * dmul; + unsigned struct_offset = this->matched_candidate->xfb_offset_floats * 4; this->buffer = this->matched_candidate->toplevel_var->data.xfb_buffer; this->offset = this->matched_candidate->toplevel_var->data.offset + array_offset + struct_offset; @@ -1189,7 +1196,14 @@ tfeedback_decl::get_num_outputs() const if (!this->is_varying()) { return 0; } - return (this->num_components() + this->location_frac + 3)/4; + + if (varying_has_user_specified_location(this->matched_candidate->toplevel_var)) { + unsigned dmul = this->is_64bit() ? 2 : 1; + unsigned rows_per_element = DIV_ROUND_UP(this->vector_elements * dmul, 4); + return this->size * this->matrix_columns * rows_per_element; + } else { + return (this->num_components() + this->location_frac + 3) / 4; + } } @@ -1299,8 +1313,50 @@ tfeedback_decl::store(struct gl_context *ctx, struct gl_shader_program *prog, used[word] |= BITSET_RANGE(start_range, end_range); } + const unsigned type_num_components = + this->vector_elements * (this->is_64bit() ? 2 : 1); + unsigned current_type_components_left = type_num_components; + while (num_components > 0) { - unsigned output_size = MIN2(num_components, 4 - location_frac); + unsigned output_size = 0; + + /* From GL_ARB_enhanced_layouts: + * + * "When an attribute variable declared using an array type is bound to + * generic attribute index <i>, the active array elements are assigned to + * consecutive generic attributes beginning with generic attribute <i>. The + * number of attributes and components assigned to each element are + * determined according to the data type of array elements and "component" + * layout qualifier (if any) specified in the declaration of the array." + * + * "When an attribute variable declared using a matrix type is bound to a + * generic attribute index <i>, its values are taken from consecutive generic + * attributes beginning with generic attribute <i>. Such matrices are + * treated as an array of column vectors with values taken from the generic + * attributes. + * This means there may be gaps in the varyings we are taking values from." + * + * Examples: + * + * | layout(location=0) dvec3[2] a; | layout(location=4) vec2[4] b; | + * | | | + * | 32b 32b 32b 32b | 32b 32b 32b 32b | + * | 0 X X Y Y | 4 X Y 0 0 | + * | 1 Z Z 0 0 | 5 X Y 0 0 | + * | 2 X X Y Y | 6 X Y 0 0 | + * | 3 Z Z 0 0 | 7 X Y 0 0 | + * + */ + if (varying_has_user_specified_location(this->matched_candidate->toplevel_var)) { + output_size = MIN3(num_components, current_type_components_left, 4); + current_type_components_left -= output_size; + if (current_type_components_left == 0) { + current_type_components_left = type_num_components; + } + } else { + output_size = MIN2(num_components, 4 - location_frac); + } + assert((info->NumOutputs == 0 && max_outputs == 0) || info->NumOutputs < max_outputs); @@ -2352,7 +2408,8 @@ public: tfeedback_candidates(tfeedback_candidates), stage(stage), toplevel_var(NULL), - varying_floats(0) + varying_floats(0), + xfb_offset_floats(0) { } @@ -2364,6 +2421,7 @@ public: this->toplevel_var = var; this->varying_floats = 0; + this->xfb_offset_floats = 0; const glsl_type *t = var->data.from_named_ifc_block ? var->get_interface_type() : var->type; if (!var->data.patch && stage == MESA_SHADER_TESS_CTRL) { @@ -2387,11 +2445,37 @@ private: = rzalloc(this->mem_ctx, tfeedback_candidate); candidate->toplevel_var = this->toplevel_var; candidate->type = type; - candidate->offset = this->varying_floats; - _mesa_hash_table_insert(this->tfeedback_candidates, - ralloc_strdup(this->mem_ctx, name), - candidate); - this->varying_floats += type->component_slots(); + + if (type->without_array()->is_64bit()) { + /* From ARB_gpu_shader_fp64: + * + * If any variable captured in transform feedback has double-precision + * components, the practical requirements for defined behavior are: + * ... + * (c) each double-precision variable captured must be aligned to a + * multiple of eight bytes relative to the beginning of a vertex. + */ + this->xfb_offset_floats = ALIGN(this->xfb_offset_floats, 2); + /* 64-bit members of structs are also aligned. */ + this->varying_floats = ALIGN(this->varying_floats, 2); + } + + candidate->xfb_offset_floats = this->xfb_offset_floats; + candidate->struct_offset_floats = this->varying_floats; + + _mesa_hash_table_insert(this->tfeedback_candidates, + ralloc_strdup(this->mem_ctx, name), + candidate); + + const unsigned component_slots = type->component_slots(); + + if (varying_has_user_specified_location(this->toplevel_var)) { + this->varying_floats += type->count_attribute_slots(false) * 4; + } else { + this->varying_floats += component_slots; + } + + this->xfb_offset_floats += component_slots; } /** @@ -2417,6 +2501,11 @@ private: * variable. */ unsigned varying_floats; + + /** + * Offset within the xfb. Counted in floats. + */ + unsigned xfb_offset_floats; }; @@ -2835,7 +2924,7 @@ assign_varying_locations(struct gl_context *ctx, matched_candidate->type->without_array()->is_64bit() ? 2 : 1; const bool lowered = (disable_xfb_packing && - !tfeedback_decls[i].is_aligned(dmul, matched_candidate->offset)) || + !tfeedback_decls[i].is_aligned(dmul, matched_candidate->struct_offset_floats)) || (matched_candidate->toplevel_var->data.explicit_location && matched_candidate->toplevel_var->data.location < VARYING_SLOT_VAR0 && (!consumer || consumer->Stage == MESA_SHADER_FRAGMENT) && @@ -2857,7 +2946,8 @@ assign_varying_locations(struct gl_context *ctx, new_candidate->toplevel_var = new_var; new_candidate->toplevel_var->data.is_unmatched_generic_inout = 1; new_candidate->type = new_var->type; - new_candidate->offset = 0; + new_candidate->struct_offset_floats = 0; + new_candidate->xfb_offset_floats = 0; _mesa_hash_table_insert(tfeedback_candidates, ralloc_strdup(mem_ctx, new_var->name), new_candidate); diff --git a/src/compiler/glsl/link_varyings.h b/src/compiler/glsl/link_varyings.h index 6f4bcdc79c5..7bad222f132 100644 --- a/src/compiler/glsl/link_varyings.h +++ b/src/compiler/glsl/link_varyings.h @@ -77,10 +77,16 @@ struct tfeedback_candidate const glsl_type *type; /** - * Offset within the toplevel variable where this varying occurs (counted - * in multiples of the size of a float). + * Offset within the toplevel variable where this varying occurs. + * Counted in floats. */ - unsigned offset; + unsigned struct_offset_floats; + + /** + * Offset within the xfb with respect to alignment requirements. + * Counted in floats. + */ + unsigned xfb_offset_floats; }; |