summaryrefslogtreecommitdiff
path: root/servers/rendering/shader_language.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'servers/rendering/shader_language.cpp')
-rw-r--r--servers/rendering/shader_language.cpp441
1 files changed, 277 insertions, 164 deletions
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index 742ad8a7bf..c6eef48dfa 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -913,6 +913,7 @@ void ShaderLanguage::clear() {
char_idx = 0;
error_set = false;
error_str = "";
+ last_const = false;
while (nodes) {
Node *n = nodes;
nodes = nodes->next;
@@ -920,7 +921,7 @@ void ShaderLanguage::clear() {
}
}
-bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_reassign, const FunctionInfo &p_function_info, const StringName &p_identifier, DataType *r_data_type, IdentifierType *r_type, bool *r_is_const, int *r_array_size, StringName *r_struct_name) {
+bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_reassign, const FunctionInfo &p_function_info, const StringName &p_identifier, DataType *r_data_type, IdentifierType *r_type, bool *r_is_const, int *r_array_size, StringName *r_struct_name, ConstantNode::Value *r_constant_value) {
if (p_function_info.built_ins.has(p_identifier)) {
if (r_data_type) {
*r_data_type = p_function_info.built_ins[p_identifier].type;
@@ -968,6 +969,9 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
if (r_struct_name) {
*r_struct_name = p_block->variables[p_identifier].struct_name;
}
+ if (r_constant_value) {
+ *r_constant_value = p_block->variables[p_identifier].value;
+ }
return true;
}
@@ -1028,6 +1032,9 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
}
if (shader->constants.has(p_identifier)) {
+ if (r_is_const) {
+ *r_is_const = true;
+ }
if (r_data_type) {
*r_data_type = shader->constants[p_identifier].type;
}
@@ -1040,6 +1047,11 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
if (r_struct_name) {
*r_struct_name = shader->constants[p_identifier].type_str;
}
+ if (r_constant_value) {
+ if (shader->constants[p_identifier].initializer && shader->constants[p_identifier].initializer->values.size() == 1) {
+ *r_constant_value = shader->constants[p_identifier].initializer->values[0];
+ }
+ }
return true;
}
@@ -3241,6 +3253,137 @@ bool ShaderLanguage::_propagate_function_call_sampler_builtin_reference(StringNa
ERR_FAIL_V(false); //bug? function not found
}
+ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_block, const FunctionInfo &p_function_info, DataType p_type, const StringName &p_struct_name, int p_array_size) {
+ DataType type = TYPE_VOID;
+ String struct_name = "";
+ int array_size = 0;
+ bool auto_size = false;
+ Token tk = _get_token();
+
+ if (tk.type == TK_CURLY_BRACKET_OPEN) {
+ auto_size = true;
+ } else {
+ if (shader->structs.has(tk.text)) {
+ type = TYPE_STRUCT;
+ struct_name = tk.text;
+ } else {
+ if (!is_token_variable_datatype(tk.type)) {
+ _set_error("Invalid data type for array");
+ return nullptr;
+ }
+ type = get_token_datatype(tk.type);
+ }
+ tk = _get_token();
+ if (tk.type == TK_BRACKET_OPEN) {
+ TkPos pos = _get_tkpos();
+ tk = _get_token();
+ if (tk.type == TK_BRACKET_CLOSE) {
+ array_size = p_array_size;
+ tk = _get_token();
+ } else {
+ _set_tkpos(pos);
+
+ Node *n = _parse_and_reduce_expression(p_block, p_function_info);
+ if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) {
+ _set_error("Expected single integer constant > 0");
+ return nullptr;
+ }
+
+ ConstantNode *cnode = (ConstantNode *)n;
+ if (cnode->values.size() == 1) {
+ array_size = cnode->values[0].sint;
+ if (array_size <= 0) {
+ _set_error("Expected single integer constant > 0");
+ return nullptr;
+ }
+ } else {
+ _set_error("Expected single integer constant > 0");
+ return nullptr;
+ }
+
+ tk = _get_token();
+ if (tk.type != TK_BRACKET_CLOSE) {
+ _set_error("Expected ']'");
+ return nullptr;
+ } else {
+ tk = _get_token();
+ }
+ }
+ } else {
+ _set_error("Expected '['");
+ return nullptr;
+ }
+
+ if (type != p_type || struct_name != p_struct_name || array_size != p_array_size) {
+ String error_str = "Cannot convert from '";
+ if (type == TYPE_STRUCT) {
+ error_str += struct_name;
+ } else {
+ error_str += get_datatype_name(type);
+ }
+ error_str += "[";
+ error_str += itos(array_size);
+ error_str += "]'";
+ error_str += " to '";
+ if (type == TYPE_STRUCT) {
+ error_str += p_struct_name;
+ } else {
+ error_str += get_datatype_name(p_type);
+ }
+ error_str += "[";
+ error_str += itos(p_array_size);
+ error_str += "]'";
+ _set_error(error_str);
+ return nullptr;
+ }
+ }
+
+ ArrayConstructNode *an = alloc_node<ArrayConstructNode>();
+ an->datatype = p_type;
+ an->struct_name = p_struct_name;
+
+ if (tk.type == TK_PARENTHESIS_OPEN || auto_size) { // initialization
+ while (true) {
+ Node *n = _parse_and_reduce_expression(p_block, p_function_info);
+ if (!n) {
+ return nullptr;
+ }
+
+ if (p_type != n->get_datatype() || p_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 nullptr;
+ }
+
+ tk = _get_token();
+ if (tk.type == TK_COMMA) {
+ an->initializer.push_back(n);
+ } 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 nullptr;
+ }
+ }
+ if (an->initializer.size() != p_array_size) {
+ _set_error("Array size mismatch");
+ return nullptr;
+ }
+ } else {
+ _set_error("Expected array initialization!");
+ return nullptr;
+ }
+
+ return an;
+}
+
ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, const FunctionInfo &p_function_info) {
Vector<Expression> expression;
@@ -3384,142 +3527,10 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
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 nullptr;
- }
- 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_function_info);
- if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) {
- _set_error("Expected single integer constant > 0");
- return nullptr;
- }
-
- 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 nullptr;
- }
- } else {
- _set_error("Expected single integer constant > 0");
- return nullptr;
- }
-
- tk = _get_token();
- if (tk.type != TK_BRACKET_CLOSE) {
- _set_error("Expected ']'");
- return nullptr;
- } else {
- tk = _get_token();
- }
- }
- } else {
- _set_error("Expected '['");
- return nullptr;
- }
-
- 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 nullptr;
- }
- }
-
- 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_function_info);
- if (!n) {
- return nullptr;
- }
-
- 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 nullptr;
- }
-
- 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 nullptr;
- }
- }
- if (an->initializer.size() != array_size) {
- _set_error("Array size mismatch");
- return nullptr;
- }
- } else {
- _set_error("Expected array initialization!");
+ nexpr = _parse_array_constructor(p_block, p_function_info, pstruct->members[i]->get_datatype(), pstruct->members[i]->struct_name, pstruct->members[i]->array_size);
+ if (!nexpr) {
return nullptr;
}
-
- nexpr = an;
} else {
nexpr = _parse_and_reduce_expression(p_block, p_function_info);
if (!nexpr) {
@@ -3722,6 +3733,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
} else {
//an identifier
+ last_const = false;
_set_tkpos(pos);
DataType data_type;
@@ -3749,6 +3761,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
_set_error("Unknown identifier in expression: " + String(identifier));
return nullptr;
}
+ last_const = is_const;
if (ident_type == IDENTIFIER_FUNCTION) {
_set_error("Can't use function as identifier: " + String(identifier));
@@ -3758,16 +3771,30 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
Node *index_expression = nullptr;
Node *call_expression = nullptr;
+ Node *assign_expression = nullptr;
if (array_size > 0) {
tk = _get_token();
- if (tk.type != TK_BRACKET_OPEN && tk.type != TK_PERIOD) {
- _set_error("Expected '[' or '.'");
+ if (tk.type != TK_BRACKET_OPEN && tk.type != TK_PERIOD && tk.type != TK_OP_ASSIGN) {
+ _set_error("Expected '[','.' or '='");
return nullptr;
}
- if (tk.type == TK_PERIOD) {
+ if (tk.type == TK_OP_ASSIGN) {
+ if (is_const) {
+ _set_error("Constants cannot be modified.");
+ return nullptr;
+ }
+ if (shader->varyings.has(identifier) && current_function != String("vertex")) {
+ _set_error("Varyings can only be assigned in vertex function.");
+ return nullptr;
+ }
+ assign_expression = _parse_array_constructor(p_block, p_function_info, data_type, struct_name, array_size);
+ if (!assign_expression) {
+ return nullptr;
+ }
+ } else if (tk.type == TK_PERIOD) {
completion_class = TAG_ARRAY;
p_block->block_tag = SubClassTag::TAG_ARRAY;
call_expression = _parse_and_reduce_expression(p_block, p_function_info);
@@ -3814,6 +3841,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
arrname->struct_name = struct_name;
arrname->index_expression = index_expression;
arrname->call_expression = call_expression;
+ arrname->assign_expression = assign_expression;
arrname->is_const = is_const;
expr = arrname;
@@ -4154,7 +4182,18 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
if (array_size > 0) {
tk = _get_token();
- if (tk.type == TK_PERIOD) {
+ if (tk.type == TK_OP_ASSIGN) {
+ if (last_const) {
+ last_const = false;
+ _set_error("Constants cannot be modified.");
+ return nullptr;
+ }
+ Node *assign_expression = _parse_array_constructor(p_block, p_function_info, member_type, member_struct_name, array_size);
+ if (!assign_expression) {
+ return nullptr;
+ }
+ mn->assign_expression = assign_expression;
+ } else if (tk.type == TK_PERIOD) {
_set_error("Nested array length() is not yet implemented");
return nullptr;
} else if (tk.type == TK_BRACKET_OPEN) {
@@ -4189,7 +4228,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
mn->index_expression = index_expression;
} else {
- _set_error("Expected '[' or '.'");
+ _set_error("Expected '[','.' or '='");
return nullptr;
}
}
@@ -5010,17 +5049,53 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
decl.name = name;
decl.size = 0U;
+ pos = _get_tkpos();
tk = _get_token();
if (tk.type == TK_BRACKET_CLOSE) {
unknown_size = true;
} else {
if (tk.type != TK_INT_CONSTANT || ((int)tk.constant) <= 0) {
+ _set_tkpos(pos);
+ Node *n = _parse_and_reduce_expression(p_block, p_function_info);
+ if (n) {
+ if (n->type == Node::TYPE_VARIABLE) {
+ VariableNode *vn = static_cast<VariableNode *>(n);
+ if (vn) {
+ ConstantNode::Value v;
+ DataType data_type;
+
+ _find_identifier(p_block, false, p_function_info, vn->name, &data_type, nullptr, &is_const, nullptr, nullptr, &v);
+
+ if (is_const) {
+ if (data_type == TYPE_INT) {
+ int32_t value = v.sint;
+ if (value > 0) {
+ node->size_expression = n;
+ decl.size = (uint32_t)value;
+ }
+ } else if (data_type == TYPE_UINT) {
+ uint32_t value = v.uint;
+ if (value > 0U) {
+ node->size_expression = n;
+ decl.size = value;
+ }
+ }
+ }
+ }
+ } else if (n->type == Node::TYPE_OPERATOR) {
+ _set_error("Array size expressions are not yet implemented.");
+ return ERR_PARSE_ERROR;
+ }
+ }
+ } else if (((int)tk.constant) > 0) {
+ decl.size = (uint32_t)tk.constant;
+ }
+
+ if (decl.size == 0U) {
_set_error("Expected integer constant > 0 or ']'");
return ERR_PARSE_ERROR;
}
-
- decl.size = ((uint32_t)tk.constant);
tk = _get_token();
if (tk.type != TK_BRACKET_CLOSE) {
@@ -5218,7 +5293,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
_set_error("Expected array initialization");
return ERR_PARSE_ERROR;
}
- if (is_const) {
+ if (node->is_const) {
_set_error("Expected initialization of constant");
return ERR_PARSE_ERROR;
}
@@ -5252,6 +5327,13 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
}
decl.initializer = n;
+ if (n->type == Node::TYPE_CONSTANT) {
+ ConstantNode *const_node = static_cast<ConstantNode *>(n);
+ if (const_node && const_node->values.size() == 1) {
+ var.value = const_node->values[0];
+ }
+ }
+
if (var.type == TYPE_STRUCT ? (var.struct_name != n->get_datatype_name()) : (var.type != n->get_datatype())) {
_set_error("Invalid assignment of '" + (n->get_datatype() == TYPE_STRUCT ? n->get_datatype_name() : get_datatype_name(n->get_datatype())) + "' to '" + (var.type == TYPE_STRUCT ? String(var.struct_name) : get_datatype_name(var.type)) + "'");
return ERR_PARSE_ERROR;
@@ -5420,18 +5502,29 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
ControlFlowNode *flow = (ControlFlowNode *)switch_block->statements[i];
if (flow) {
if (flow->flow_op == FLOW_OP_CASE) {
- ConstantNode *n2 = static_cast<ConstantNode *>(flow->expressions[0]);
- if (!n2) {
- return ERR_PARSE_ERROR;
- }
- if (n2->values.empty()) {
- return ERR_PARSE_ERROR;
- }
- if (constants.has(n2->values[0].sint)) {
- _set_error("Duplicated case label: '" + itos(n2->values[0].sint) + "'");
- return ERR_PARSE_ERROR;
+ if (flow->expressions[0]->type == Node::TYPE_CONSTANT) {
+ ConstantNode *cn = static_cast<ConstantNode *>(flow->expressions[0]);
+ if (!cn || cn->values.empty()) {
+ return ERR_PARSE_ERROR;
+ }
+ if (constants.has(cn->values[0].sint)) {
+ _set_error("Duplicated case label: '" + itos(cn->values[0].sint) + "'");
+ return ERR_PARSE_ERROR;
+ }
+ constants.insert(cn->values[0].sint);
+ } else if (flow->expressions[0]->type == Node::TYPE_VARIABLE) {
+ VariableNode *vn = static_cast<VariableNode *>(flow->expressions[0]);
+ if (!vn) {
+ return ERR_PARSE_ERROR;
+ }
+ ConstantNode::Value v;
+ _find_identifier(p_block, false, p_function_info, vn->name, nullptr, nullptr, nullptr, nullptr, nullptr, &v);
+ if (constants.has(v.sint)) {
+ _set_error("Duplicated case label: '" + itos(v.sint) + "'");
+ return ERR_PARSE_ERROR;
+ }
+ constants.insert(v.sint);
}
- constants.insert(n2->values[0].sint);
} else if (flow->flow_op == FLOW_OP_DEFAULT) {
continue;
} else {
@@ -5467,12 +5560,38 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
tk = _get_token();
}
+ Node *n = nullptr;
+
if (tk.type != TK_INT_CONSTANT) {
- _set_error("Expected integer constant");
- return ERR_PARSE_ERROR;
- }
+ bool correct_constant_expression = false;
+ DataType data_type;
+
+ if (tk.type == TK_IDENTIFIER) {
+ bool is_const;
+ _find_identifier(p_block, false, p_function_info, tk.text, &data_type, nullptr, &is_const);
+ if (is_const) {
+ if (data_type == TYPE_INT) {
+ correct_constant_expression = true;
+ }
+ }
+ }
+ if (!correct_constant_expression) {
+ _set_error("Expected integer constant");
+ return ERR_PARSE_ERROR;
+ }
+
+ VariableNode *vn = alloc_node<VariableNode>();
+ vn->name = tk.text;
+ n = vn;
+ } else {
+ ConstantNode::Value v;
+ v.sint = (int)tk.constant * sign;
- int constant = (int)tk.constant * sign;
+ ConstantNode *cn = alloc_node<ConstantNode>();
+ cn->values.push_back(v);
+ cn->datatype = TYPE_INT;
+ n = cn;
+ }
tk = _get_token();
@@ -5484,12 +5603,6 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
ControlFlowNode *cf = alloc_node<ControlFlowNode>();
cf->flow_op = FLOW_OP_CASE;
- ConstantNode *n = alloc_node<ConstantNode>();
- ConstantNode::Value v;
- v.sint = constant;
- n->values.push_back(v);
- n->datatype = TYPE_INT;
-
BlockNode *case_block = alloc_node<BlockNode>();
case_block->block_type = BlockNode::BLOCK_TYPE_CASE;
case_block->parent_block = p_block;