summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRĂ©mi Verschelde <remi@verschelde.fr>2021-10-08 12:37:05 +0200
committerGitHub <noreply@github.com>2021-10-08 12:37:05 +0200
commit96767c18f89bc12232f4ce7016c797ebb0aaeb19 (patch)
tree78685ec08057cefcc0977338f9b2a5c43fe3db3c
parent9b34442d93298c9e15f2068e2ba955c411aeb3af (diff)
parentb1ac3e256f771cb64cb8cd2deabacf3d0df283d0 (diff)
Merge pull request #53527 from Chaosus/shader_array
-rw-r--r--servers/rendering/shader_language.cpp355
-rw-r--r--servers/rendering/shader_language.h4
2 files changed, 222 insertions, 137 deletions
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index 713d927c50..ebebb849d0 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -3873,6 +3873,116 @@ bool ShaderLanguage::_propagate_function_call_sampler_builtin_reference(StringNa
ERR_FAIL_V(false); //bug? function not found
}
+ShaderLanguage::Node *ShaderLanguage::_parse_array_size(BlockNode *p_block, const FunctionInfo &p_function_info, int &r_array_size) {
+ int array_size = 0;
+
+ 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;
+ bool is_const = false;
+
+ _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) {
+ array_size = value;
+ }
+ } else if (data_type == TYPE_UINT) {
+ uint32_t value = v.uint;
+ if (value > 0U) {
+ array_size = value;
+ }
+ }
+ }
+ }
+ } else if (n->type == Node::TYPE_OPERATOR) {
+ _set_error("Array size expressions are not yet implemented.");
+ return nullptr;
+ }
+ }
+
+ r_array_size = array_size;
+ return n;
+}
+
+Error ShaderLanguage::_parse_global_array_size(int &r_array_size) {
+ if (r_array_size > 0) {
+ _set_error("Array size is already defined!");
+ return ERR_PARSE_ERROR;
+ }
+ TkPos pos = _get_tkpos();
+ Token tk = _get_token();
+
+ int array_size = 0;
+
+ if (tk.type != TK_INT_CONSTANT || ((int)tk.constant) <= 0) {
+ _set_tkpos(pos);
+ Node *n = _parse_array_size(nullptr, FunctionInfo(), array_size);
+ if (!n) {
+ return ERR_PARSE_ERROR;
+ }
+ } else if (((int)tk.constant) > 0) {
+ array_size = (uint32_t)tk.constant;
+ }
+
+ if (array_size <= 0) {
+ _set_error("Expected single integer constant > 0");
+ return ERR_PARSE_ERROR;
+ }
+
+ tk = _get_token();
+ if (tk.type != TK_BRACKET_CLOSE) {
+ _set_error("Expected ']'");
+ return ERR_PARSE_ERROR;
+ }
+
+ r_array_size = array_size;
+ return OK;
+}
+
+Error ShaderLanguage::_parse_local_array_size(BlockNode *p_block, const FunctionInfo &p_function_info, ArrayDeclarationNode *p_node, ArrayDeclarationNode::Declaration *p_decl, int &r_array_size, bool &r_is_unknown_size) {
+ TkPos pos = _get_tkpos();
+ Token tk = _get_token();
+
+ if (tk.type == TK_BRACKET_CLOSE) {
+ r_is_unknown_size = true;
+ } else {
+ if (tk.type != TK_INT_CONSTANT || ((int)tk.constant) <= 0) {
+ _set_tkpos(pos);
+ int array_size = 0;
+ Node *n = _parse_array_size(p_block, p_function_info, array_size);
+ if (!n) {
+ return ERR_PARSE_ERROR;
+ }
+ p_decl->size = array_size;
+ p_node->size_expression = n;
+ } else if (((int)tk.constant) > 0) {
+ p_decl->size = (uint32_t)tk.constant;
+ }
+
+ if (p_decl->size <= 0) {
+ _set_error("Expected single integer constant > 0");
+ return ERR_PARSE_ERROR;
+ }
+
+ tk = _get_token();
+ if (tk.type != TK_BRACKET_CLOSE) {
+ _set_error("Expected ']'");
+ return ERR_PARSE_ERROR;
+ }
+
+ r_array_size = p_decl->size;
+ }
+
+ return OK;
+}
+
ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_block, const FunctionInfo &p_function_info) {
DataType type = TYPE_VOID;
String struct_name = "";
@@ -5885,11 +5995,46 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
Node *vardecl = nullptr;
while (true) {
- if (tk.type != TK_IDENTIFIER) {
- _set_error("Expected identifier after type");
+ bool unknown_size = false;
+ int array_size = 0;
+
+ ArrayDeclarationNode *anode = nullptr;
+ ArrayDeclarationNode::Declaration adecl;
+
+ if (tk.type != TK_IDENTIFIER && tk.type != TK_BRACKET_OPEN) {
+ _set_error("Expected identifier or '[' after type.");
return ERR_PARSE_ERROR;
}
+ if (tk.type == TK_BRACKET_OPEN) {
+ anode = alloc_node<ArrayDeclarationNode>();
+
+ if (is_struct) {
+ anode->struct_name = struct_name;
+ anode->datatype = TYPE_STRUCT;
+ } else {
+ anode->datatype = type;
+ }
+
+ anode->precision = precision;
+ anode->is_const = is_const;
+ vardecl = (Node *)anode;
+
+ adecl.size = 0U;
+ adecl.single_expression = false;
+
+ Error error = _parse_local_array_size(p_block, p_function_info, anode, &adecl, array_size, unknown_size);
+ if (error != OK) {
+ return error;
+ }
+ tk = _get_token();
+
+ if (tk.type != TK_IDENTIFIER) {
+ _set_error("Expected identifier!");
+ return ERR_PARSE_ERROR;
+ }
+ }
+
StringName name = tk.text;
ShaderLanguage::IdentifierType itype;
if (_find_identifier(p_block, true, p_function_info, name, (ShaderLanguage::DataType *)nullptr, &itype)) {
@@ -5899,6 +6044,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
}
}
+ adecl.name = name;
+
#ifdef DEBUG_ENABLED
if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_LOCAL_VARIABLE_FLAG)) {
if (p_block && p_block->parent_function) {
@@ -5917,95 +6064,47 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
var.type = type;
var.precision = precision;
var.line = tk_line;
- var.array_size = 0;
+ var.array_size = array_size;
var.is_const = is_const;
var.struct_name = struct_name;
tk = _get_token();
if (tk.type == TK_BRACKET_OPEN) {
- bool unknown_size = false;
+ if (var.array_size > 0 || unknown_size) {
+ _set_error("Array size is already defined!");
+ return ERR_PARSE_ERROR;
+ }
if (RenderingServer::get_singleton()->is_low_end() && is_const) {
_set_error("Local const arrays are supported only on high-end platform!");
return ERR_PARSE_ERROR;
}
- ArrayDeclarationNode *node = alloc_node<ArrayDeclarationNode>();
+ anode = alloc_node<ArrayDeclarationNode>();
if (is_struct) {
- node->struct_name = struct_name;
- node->datatype = TYPE_STRUCT;
+ anode->struct_name = struct_name;
+ anode->datatype = TYPE_STRUCT;
} else {
- node->datatype = type;
+ anode->datatype = type;
}
- node->precision = precision;
- node->is_const = is_const;
- vardecl = (Node *)node;
+ anode->precision = precision;
+ anode->is_const = is_const;
+ vardecl = (Node *)anode;
- ArrayDeclarationNode::Declaration decl;
- decl.name = name;
- decl.size = 0U;
- decl.single_expression = false;
+ adecl.size = 0U;
+ adecl.single_expression = false;
- 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;
- }
- tk = _get_token();
-
- if (tk.type != TK_BRACKET_CLOSE) {
- _set_error("Expected ']'");
- return ERR_PARSE_ERROR;
- }
- var.array_size = decl.size;
+ Error error = _parse_local_array_size(p_block, p_function_info, anode, &adecl, var.array_size, unknown_size);
+ if (error != OK) {
+ return error;
}
+ tk = _get_token();
+ }
+ if (var.array_size > 0 || unknown_size) {
bool full_def = false;
- tk = _get_token();
if (tk.type == TK_OP_ASSIGN) {
if (RenderingServer::get_singleton()->is_low_end()) {
_set_error("Array initialization is supported only on high-end platform!");
@@ -6024,7 +6123,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
return ERR_PARSE_ERROR;
} else {
if (unknown_size) {
- decl.size = n->get_array_size();
+ adecl.size = n->get_array_size();
var.array_size = n->get_array_size();
}
@@ -6032,8 +6131,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
return ERR_PARSE_ERROR;
}
- decl.single_expression = true;
- decl.initializer.push_back(n);
+ adecl.single_expression = true;
+ adecl.initializer.push_back(n);
}
tk = _get_token();
@@ -6172,7 +6271,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
return ERR_PARSE_ERROR;
}
- if (node->is_const && n->type == Node::TYPE_OPERATOR && ((OperatorNode *)n)->op == OP_CALL) {
+ if (anode->is_const && n->type == Node::TYPE_OPERATOR && ((OperatorNode *)n)->op == OP_CALL) {
_set_error("Expected constant expression");
return ERR_PARSE_ERROR;
}
@@ -6183,13 +6282,13 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
tk = _get_token();
if (tk.type == TK_COMMA) {
- decl.initializer.push_back(n);
+ adecl.initializer.push_back(n);
continue;
} else if (!curly && tk.type == TK_PARENTHESIS_CLOSE) {
- decl.initializer.push_back(n);
+ adecl.initializer.push_back(n);
break;
} else if (curly && tk.type == TK_CURLY_BRACKET_CLOSE) {
- decl.initializer.push_back(n);
+ adecl.initializer.push_back(n);
break;
} else {
if (curly) {
@@ -6201,9 +6300,9 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
}
}
if (unknown_size) {
- decl.size = decl.initializer.size();
- var.array_size = decl.initializer.size();
- } else if (decl.initializer.size() != var.array_size) {
+ adecl.size = adecl.initializer.size();
+ var.array_size = adecl.initializer.size();
+ } else if (adecl.initializer.size() != var.array_size) {
_set_error("Array size mismatch");
return ERR_PARSE_ERROR;
}
@@ -6215,13 +6314,13 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
_set_error("Expected array initialization");
return ERR_PARSE_ERROR;
}
- if (node->is_const) {
+ if (anode->is_const) {
_set_error("Expected initialization of constant");
return ERR_PARSE_ERROR;
}
}
- node->declarations.push_back(decl);
+ anode->declarations.push_back(adecl);
} else if (tk.type == TK_OP_ASSIGN) {
VariableDeclarationNode *node = alloc_node<VariableDeclarationNode>();
if (is_struct) {
@@ -7068,8 +7167,23 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
_set_error("void datatype not allowed here");
return ERR_PARSE_ERROR;
}
-
tk = _get_token();
+
+ if (tk.type != TK_IDENTIFIER && tk.type != TK_BRACKET_OPEN) {
+ _set_error("Expected identifier or '['.");
+ return ERR_PARSE_ERROR;
+ }
+
+ int array_size = 0;
+
+ if (tk.type == TK_BRACKET_OPEN) {
+ Error error = _parse_global_array_size(array_size);
+ if (error != OK) {
+ return error;
+ }
+ tk = _get_token();
+ }
+
if (tk.type != TK_IDENTIFIER) {
_set_error("Expected identifier!");
return ERR_PARSE_ERROR;
@@ -7080,41 +7194,29 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
member->datatype = type;
member->struct_name = struct_name;
member->name = tk.text;
+ member->array_size = array_size;
if (member_names.has(member->name)) {
_set_error("Redefinition of '" + String(member->name) + "'");
return ERR_PARSE_ERROR;
}
member_names.insert(member->name);
-
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;
+ if (tk.type == TK_BRACKET_OPEN) {
+ Error error = _parse_global_array_size(member->array_size);
+ if (error != OK) {
+ return error;
}
+ tk = _get_token();
}
- st_node->members.push_back(member);
if (tk.type != TK_SEMICOLON) {
- _set_error("Expected ']' or ';'");
+ _set_error("Expected ';'");
return ERR_PARSE_ERROR;
}
+
+ st_node->members.push_back(member);
member_count++;
}
}
@@ -7223,23 +7325,17 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
tk = _get_token();
- if (tk.type == TK_BRACKET_OPEN) {
- tk = _get_token();
-
- if (tk.type == TK_INT_CONSTANT && tk.constant > 0) {
- array_size = (int)tk.constant;
+ if (tk.type != TK_IDENTIFIER && tk.type != TK_BRACKET_OPEN) {
+ _set_error("Expected identifier or '['.");
+ return ERR_PARSE_ERROR;
+ }
- tk = _get_token();
- if (tk.type == TK_BRACKET_CLOSE) {
- tk = _get_token();
- } else {
- _set_error("Expected ']'");
- return ERR_PARSE_ERROR;
- }
- } else {
- _set_error("Expected integer constant > 0");
- return ERR_PARSE_ERROR;
+ if (tk.type == TK_BRACKET_OPEN) {
+ Error error = _parse_global_array_size(array_size);
+ if (error != OK) {
+ return error;
}
+ tk = _get_token();
}
if (tk.type != TK_IDENTIFIER) {
@@ -7283,26 +7379,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
tk = _get_token();
if (tk.type == TK_BRACKET_OPEN) {
- if (uniform2.array_size > 0) {
- _set_error("Array size is already defined!");
- return ERR_PARSE_ERROR;
+ Error error = _parse_global_array_size(uniform2.array_size);
+ if (error != OK) {
+ return error;
}
tk = _get_token();
-
- if (tk.type == TK_INT_CONSTANT && tk.constant > 0) {
- uniform2.array_size = (int)tk.constant;
-
- tk = _get_token();
- if (tk.type == TK_BRACKET_CLOSE) {
- tk = _get_token();
- } else {
- _set_error("Expected ']'");
- return ERR_PARSE_ERROR;
- }
- } else {
- _set_error("Expected integer constant > 0");
- return ERR_PARSE_ERROR;
- }
}
if (is_sampler_type(type)) {
diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h
index 1444546f05..4740da0c37 100644
--- a/servers/rendering/shader_language.h
+++ b/servers/rendering/shader_language.h
@@ -979,6 +979,10 @@ private:
bool _validate_varying_using(ShaderNode::Varying &p_varying, String *r_message);
bool _check_node_constness(const Node *p_node) const;
+ Node *_parse_array_size(BlockNode *p_block, const FunctionInfo &p_function_info, int &r_array_size);
+ Error _parse_global_array_size(int &r_array_size);
+ Error _parse_local_array_size(BlockNode *p_block, const FunctionInfo &p_function_info, ArrayDeclarationNode *p_node, ArrayDeclarationNode::Declaration *p_decl, int &r_array_size, bool &r_is_unknown_size);
+
Node *_parse_expression(BlockNode *p_block, const FunctionInfo &p_function_info);
Node *_parse_array_constructor(BlockNode *p_block, const FunctionInfo &p_function_info);
Node *_parse_array_constructor(BlockNode *p_block, const FunctionInfo &p_function_info, DataType p_type, const StringName &p_struct_name, int p_array_size);