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>
This commit is contained in:
Danylo Piliaiev
2019-10-10 19:11:00 +03:00
committed by Marge Bot
parent c432cb672a
commit 67e33db4a6
2 changed files with 111 additions and 15 deletions

View File

@@ -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,8 +1196,15 @@ tfeedback_decl::get_num_outputs() const
if (!this->is_varying()) {
return 0;
}
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;
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);
this->varying_floats += type->component_slots();
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);

View File

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