ARB_shader_storage_buffer_object extension (promoted to core in 4.3) allows us
to call .length() method on arrays declared without an explicit size. The length is
determined at link time as a maximum array access.
Fixes:
273f61a0051a ("glsl: Add parser/compiler support for unsized array's length()")
Signed-off-by: Yevhenii Kolesnikov <yevhenii.kolesnikov@globallogic.com>
Reviewed-by: Timothy Arceri <tarceri@itsqueeze.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/11952>
case ir_unop_get_buffer_size:
case ir_unop_ssbo_unsized_array_length:
+ case ir_unop_implicitly_sized_array_length:
this->type = glsl_type::int_type;
break;
# of its length.
operation("ssbo_unsized_array_length", 1),
+ # Calculate length of an implicitly sized array.
+ # This opcode is going to be replaced with a constant expression at link
+ # time.
+ operation("implicitly_sized_array_length", 1),
+
# 64-bit integer packing ops.
operation("pack_int_2x32", 1, printable_name="packInt2x32", source_types=(int_type,), dest_type=int64_type, c_expression="data.u64[0] = pack_2x32(op[0]->value.u[0], op[0]->value.u[1])", flags=frozenset((horizontal_operation, non_assign_operation))),
operation("pack_uint_2x32", 1, printable_name="packUint2x32", source_types=(uint_type,), dest_type=uint64_type, c_expression="data.u64[0] = pack_2x32(op[0]->value.u[0], op[0]->value.u[1])", flags=frozenset((horizontal_operation, non_assign_operation))),
assert(ir->operands[0]->type->is_unsized_array());
break;
+ case ir_unop_implicitly_sized_array_length:
+ assert(ir->type == glsl_type::int_type);
+ assert(ir->operands[0]->type->is_array());
+ break;
+
case ir_unop_d2f:
assert(ir->operands[0]->type->is_double());
assert(ir->type->is_float());
}
};
+class array_length_to_const_visitor : public ir_rvalue_visitor {
+public:
+ array_length_to_const_visitor()
+ {
+ this->progress = false;
+ }
+
+ virtual ~array_length_to_const_visitor()
+ {
+ /* empty */
+ }
+
+ bool progress;
+
+ virtual void handle_rvalue(ir_rvalue **rvalue)
+ {
+ if (*rvalue == NULL || (*rvalue)->ir_type != ir_type_expression)
+ return;
+
+ ir_expression *expr = (*rvalue)->as_expression();
+ if (expr) {
+ if (expr->operation == ir_unop_implicitly_sized_array_length) {
+ assert(!expr->operands[0]->type->is_unsized_array());
+ ir_constant *constant = new(expr)
+ ir_constant(expr->operands[0]->type->array_size());
+ if (constant) {
+ *rvalue = constant;
+ }
+ }
+ }
+ }
+};
+
/**
* Visitor that determines the highest stream id to which a (geometry) shader
* emits vertices. It also checks whether End{Stream}Primitive is ever called.
v.run(linked->ir);
v.fixup_unnamed_interface_types();
+ /* Now that we know the sizes of all the arrays, we can replace .length()
+ * calls with a constant expression.
+ */
+ array_length_to_const_visitor len_v;
+ len_v.run(linked->ir);
+
/* Link up uniform blocks defined within this stage. */
link_uniform_blocks(mem_ctx, ctx, prog, linked, &ubo_blocks,
&num_ubo_blocks, &ssbo_blocks, &num_ssbo_blocks);
break;
case ir_unop_ssbo_unsized_array_length:
+ case ir_unop_implicitly_sized_array_length:
case ir_quadop_vector:
/* This operation should have already been handled.
*/
case ir_binop_carry:
case ir_binop_borrow:
case ir_unop_ssbo_unsized_array_length:
+ case ir_unop_implicitly_sized_array_length:
case ir_unop_atan:
case ir_binop_atan2:
case ir_unop_clz: