Merge pull request #36141 from Chaosus/shader_struct_member_arrays

Added support for arrays as shader struct members
This commit is contained in:
Yuri Roubinsky 2020-02-12 20:12:05 +03:00 committed by GitHub
commit 4aa31a2851
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 300 additions and 16 deletions

View file

@ -332,6 +332,11 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener
}
struct_code += " ";
struct_code += m->name;
if (m->array_size > 0) {
struct_code += "[";
struct_code += itos(m->array_size);
struct_code += "]";
}
struct_code += ";\n";
}
struct_code += "}";
@ -558,6 +563,26 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener
}
}
} break;
case SL::Node::TYPE_ARRAY_CONSTRUCT: {
SL::ArrayConstructNode *arr_con_node = (SL::ArrayConstructNode *)p_node;
int sz = arr_con_node->initializer.size();
if (acnode->datatype == SL::TYPE_STRUCT) {
code += _mkid(arr_con_node->struct_name);
} else {
code += _typestr(arr_con_node->datatype);
}
code += "[";
code += itos(arr_con_node->initializer.size());
code += "]";
code += "(";
for (int i = 0; i < sz; i++) {
code += _dump_node_code(arr_con_node->initializer[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
if (i != sz - 1) {
code += ", ";
}
}
code += ")";
} break;
case SL::Node::TYPE_ARRAY_DECLARATION: {
SL::ArrayDeclarationNode *arr_dec_node = (SL::ArrayDeclarationNode *)p_node;
@ -898,6 +923,11 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener
code += _dump_node_code(member_node->owner, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
code += ".";
code += member_node->name;
if (member_node->index_expression != NULL) {
code += "[";
code += _dump_node_code(member_node->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
code += "]";
}
} break;
}

View file

@ -390,6 +390,11 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
}
struct_code += " ";
struct_code += m->name;
if (m->array_size > 0) {
struct_code += "[";
struct_code += itos(m->array_size);
struct_code += "]";
}
struct_code += ";\n";
}
struct_code += "}";
@ -701,6 +706,26 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
}
} break;
case SL::Node::TYPE_ARRAY_CONSTRUCT: {
SL::ArrayConstructNode *acnode = (SL::ArrayConstructNode *)p_node;
int sz = acnode->initializer.size();
if (acnode->datatype == SL::TYPE_STRUCT) {
code += _mkid(acnode->struct_name);
} else {
code += _typestr(acnode->datatype);
}
code += "[";
code += itos(acnode->initializer.size());
code += "]";
code += "(";
for (int i = 0; i < sz; i++) {
code += _dump_node_code(acnode->initializer[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
if (i != sz - 1) {
code += ", ";
}
}
code += ")";
} break;
case SL::Node::TYPE_ARRAY_DECLARATION: {
SL::ArrayDeclarationNode *adnode = (SL::ArrayDeclarationNode *)p_node;
@ -1000,6 +1025,11 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
case SL::Node::TYPE_MEMBER: {
SL::MemberNode *mnode = (SL::MemberNode *)p_node;
code = _dump_node_code(mnode->owner, p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + "." + mnode->name;
if (mnode->index_expression != NULL) {
code += "[";
code += _dump_node_code(mnode->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
code += "]";
}
} break;
}

View file

@ -3200,18 +3200,160 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
func->arguments.push_back(funcname);
for (int i = 0; i < pstruct->members.size(); i++) {
Node *nexpr = _parse_and_reduce_expression(p_block, p_builtin_types);
Node *nexpr;
if (pstruct->members[i]->array_size != 0) {
DataType type = pstruct->members[i]->get_datatype();
String struct_name = pstruct->members[i]->struct_name;
int array_size = pstruct->members[i]->array_size;
DataType type2;
String struct_name2 = "";
int array_size2 = 0;
bool auto_size = false;
tk = _get_token();
if (tk.type == TK_CURLY_BRACKET_OPEN) {
auto_size = true;
} else {
if (shader->structs.has(tk.text)) {
type2 = TYPE_STRUCT;
struct_name2 = tk.text;
} else {
if (!is_token_variable_datatype(tk.type)) {
_set_error("Invalid data type for array");
return NULL;
}
type2 = get_token_datatype(tk.type);
}
tk = _get_token();
if (tk.type == TK_BRACKET_OPEN) {
TkPos pos2 = _get_tkpos();
tk = _get_token();
if (tk.type == TK_BRACKET_CLOSE) {
array_size2 = array_size;
tk = _get_token();
} else {
_set_tkpos(pos2);
Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) {
_set_error("Expected single integer constant > 0");
return NULL;
}
ConstantNode *cnode = (ConstantNode *)n;
if (cnode->values.size() == 1) {
array_size2 = cnode->values[0].sint;
if (array_size2 <= 0) {
_set_error("Expected single integer constant > 0");
return NULL;
}
} else {
_set_error("Expected single integer constant > 0");
return NULL;
}
tk = _get_token();
if (tk.type != TK_BRACKET_CLOSE) {
_set_error("Expected ']'");
return NULL;
} else {
tk = _get_token();
}
}
} else {
_set_error("Expected '['");
return NULL;
}
if (type != type2 || struct_name != struct_name2 || array_size != array_size2) {
String error_str = "Cannot convert from '";
if (type2 == TYPE_STRUCT) {
error_str += struct_name2;
} else {
error_str += get_datatype_name(type2);
}
error_str += "[";
error_str += itos(array_size2);
error_str += "]'";
error_str += " to '";
if (type == TYPE_STRUCT) {
error_str += struct_name;
} else {
error_str += get_datatype_name(type);
}
error_str += "[";
error_str += itos(array_size);
error_str += "]'";
_set_error(error_str);
return NULL;
}
}
ArrayConstructNode *an = alloc_node<ArrayConstructNode>();
an->datatype = type;
an->struct_name = struct_name;
if (tk.type == TK_PARENTHESIS_OPEN || auto_size) { // initialization
while (true) {
Node *n = _parse_and_reduce_expression(p_block, p_builtin_types);
if (!n) {
return NULL;
}
if (type != n->get_datatype() || struct_name != n->get_datatype_name()) {
_set_error("Invalid assignment of '" + (n->get_datatype() == TYPE_STRUCT ? n->get_datatype_name() : get_datatype_name(n->get_datatype())) + "' to '" + (type == TYPE_STRUCT ? struct_name : get_datatype_name(type)) + "'");
return NULL;
}
tk = _get_token();
if (tk.type == TK_COMMA) {
an->initializer.push_back(n);
continue;
} else if (!auto_size && tk.type == TK_PARENTHESIS_CLOSE) {
an->initializer.push_back(n);
break;
} else if (auto_size && tk.type == TK_CURLY_BRACKET_CLOSE) {
an->initializer.push_back(n);
break;
} else {
if (auto_size)
_set_error("Expected '}' or ','");
else
_set_error("Expected ')' or ','");
return NULL;
}
}
if (an->initializer.size() != array_size) {
_set_error("Array size mismatch");
return NULL;
}
} else {
_set_error("Expected array initialization!");
return NULL;
}
nexpr = an;
} else {
nexpr = _parse_and_reduce_expression(p_block, p_builtin_types);
if (!nexpr) {
return NULL;
}
Node *node = pstruct->members[i];
if (!_compare_datatypes_in_nodes(pstruct->members[i], nexpr)) {
String type_name = nexpr->get_datatype() == TYPE_STRUCT ? nexpr->get_datatype_name() : get_datatype_name(nexpr->get_datatype());
String type_name2 = node->get_datatype() == TYPE_STRUCT ? node->get_datatype_name() : get_datatype_name(node->get_datatype());
_set_error("Invalid assignment of '" + type_name + "' to '" + type_name2 + "'");
return NULL;
}
}
if (i + 1 < pstruct->members.size()) {
tk = _get_token();
@ -3463,7 +3605,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
expr = varname;
}
}
} else if (tk.type == TK_OP_ADD) {
continue; //this one does nothing
} else if (tk.type == TK_OP_SUB || tk.type == TK_OP_NOT || tk.type == TK_OP_BIT_INVERT || tk.type == TK_OP_INCREMENT || tk.type == TK_OP_DECREMENT) {
@ -3482,7 +3623,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
expression.push_back(e);
continue;
} else {
_set_error("Expected expression, found: " + get_token_text(tk));
return NULL;
@ -3526,6 +3666,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
bool ok = true;
DataType member_type = TYPE_VOID;
StringName member_struct_name = "";
int array_size = 0;
switch (dt) {
case TYPE_STRUCT: {
ok = false;
@ -3535,6 +3676,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
for (List<MemberNode *>::Element *E = n->members.front(); E; E = E->next()) {
if (String(E->get()->name) == member_name) {
member_type = E->get()->datatype;
array_size = E->get()->array_size;
if (member_type == TYPE_STRUCT) {
member_struct_name = E->get()->struct_name;
}
@ -3673,8 +3815,52 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
mn->datatype = member_type;
mn->base_struct_name = st;
mn->struct_name = member_struct_name;
mn->array_size = array_size;
mn->name = ident;
mn->owner = expr;
if (array_size > 0) {
tk = _get_token();
if (tk.type == TK_PERIOD) {
_set_error("Nested array length() is not yet implemented");
return NULL;
} else if (tk.type == TK_BRACKET_OPEN) {
Node *index_expression = _parse_and_reduce_expression(p_block, p_builtin_types);
if (!index_expression)
return NULL;
if (index_expression->get_datatype() != TYPE_INT && index_expression->get_datatype() != TYPE_UINT) {
_set_error("Only integer expressions are allowed for indexing");
return NULL;
}
if (index_expression->type == Node::TYPE_CONSTANT) {
ConstantNode *cnode = (ConstantNode *)index_expression;
if (cnode) {
if (!cnode->values.empty()) {
int value = cnode->values[0].sint;
if (value < 0 || value >= array_size) {
_set_error(vformat("Index [%s] out of range [%s..%s]", value, 0, array_size - 1));
return NULL;
}
}
}
}
tk = _get_token();
if (tk.type != TK_BRACKET_CLOSE) {
_set_error("Expected ']'");
return NULL;
}
mn->index_expression = index_expression;
} else {
_set_error("Expected '[' or '.'");
return NULL;
}
}
expr = mn;
//todo
@ -3769,7 +3955,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
break;
default: {
_set_error("Object of type '" + get_datatype_name(expr->get_datatype()) + "' can't be indexed");
_set_error("Object of type '" + (expr->get_datatype() == TYPE_STRUCT ? expr->get_datatype_name() : get_datatype_name(expr->get_datatype())) + "' can't be indexed");
return NULL;
}
}
@ -5353,13 +5539,35 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
member->datatype = type;
member->struct_name = struct_name;
member->name = tk.text;
st_node->members.push_back(member);
tk = _get_token();
if (tk.type == TK_BRACKET_OPEN) {
tk = _get_token();
if (tk.type == TK_INT_CONSTANT && tk.constant > 0) {
member->array_size = (int)tk.constant;
tk = _get_token();
if (tk.type == TK_BRACKET_CLOSE) {
tk = _get_token();
if (tk.type != TK_SEMICOLON) {
_set_error("Expected ';'");
return ERR_PARSE_ERROR;
}
} else {
_set_error("Expected ']'");
return ERR_PARSE_ERROR;
}
} else {
_set_error("Expected single integer constant > 0");
return ERR_PARSE_ERROR;
}
}
st_node->members.push_back(member);
if (tk.type != TK_SEMICOLON) {
_set_error("Expected ']' or ';'");
return ERR_PARSE_ERROR;
}
member_count++;
}
}

View file

@ -332,6 +332,7 @@ public:
TYPE_MEMBER,
TYPE_ARRAY,
TYPE_ARRAY_DECLARATION,
TYPE_ARRAY_CONSTRUCT,
TYPE_STRUCT,
};
@ -427,6 +428,17 @@ public:
is_const(false) {}
};
struct ArrayConstructNode : public Node {
DataType datatype;
String struct_name;
Vector<Node *> initializer;
ArrayConstructNode() :
Node(TYPE_ARRAY_CONSTRUCT),
datatype(TYPE_VOID) {
}
};
struct ArrayDeclarationNode : public Node {
DataPrecision precision;
DataType datatype;
@ -520,9 +532,11 @@ public:
StringName base_struct_name;
DataPrecision precision;
DataType datatype;
int array_size;
StringName struct_name;
StringName name;
Node *owner;
Node *index_expression;
virtual DataType get_datatype() const { return datatype; }
virtual String get_datatype_name() const { return String(struct_name); }
@ -531,7 +545,9 @@ public:
Node(TYPE_MEMBER),
basetype(TYPE_VOID),
datatype(TYPE_VOID),
owner(NULL) {}
array_size(0),
owner(NULL),
index_expression(NULL) {}
};
struct StructNode : public Node {