[3.x] Implemented global const array to shaders
This commit is contained in:
parent
cc194f68e4
commit
1e191847c7
3 changed files with 272 additions and 26 deletions
|
@ -560,17 +560,23 @@ String ShaderCompilerGLES3::_dump_node_code(const SL::Node *p_node, int p_level,
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < pnode->vconstants.size(); i++) {
|
for (int i = 0; i < pnode->vconstants.size(); i++) {
|
||||||
|
const SL::ShaderNode::Constant &cnode = pnode->vconstants[i];
|
||||||
String gcode;
|
String gcode;
|
||||||
gcode += "const ";
|
gcode += "const ";
|
||||||
if (pnode->vconstants[i].type == SL::TYPE_STRUCT) {
|
if (pnode->vconstants[i].type == SL::TYPE_STRUCT) {
|
||||||
gcode += _mkid(pnode->vconstants[i].type_str);
|
gcode += _mkid(cnode.type_str);
|
||||||
} else {
|
} else {
|
||||||
gcode += _prestr(pnode->vconstants[i].precision);
|
gcode += _prestr(cnode.precision);
|
||||||
gcode += _typestr(pnode->vconstants[i].type);
|
gcode += _typestr(cnode.type);
|
||||||
|
}
|
||||||
|
gcode += " " + _mkid(String(cnode.name));
|
||||||
|
if (cnode.array_size > 0) {
|
||||||
|
gcode += "[";
|
||||||
|
gcode += itos(cnode.array_size);
|
||||||
|
gcode += "]";
|
||||||
}
|
}
|
||||||
gcode += " " + _mkid(String(pnode->vconstants[i].name));
|
|
||||||
gcode += "=";
|
gcode += "=";
|
||||||
gcode += _dump_node_code(pnode->vconstants[i].initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
|
gcode += _dump_node_code(cnode.initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
|
||||||
gcode += ";\n";
|
gcode += ";\n";
|
||||||
r_gen_code.vertex_global += gcode;
|
r_gen_code.vertex_global += gcode;
|
||||||
r_gen_code.fragment_global += gcode;
|
r_gen_code.fragment_global += gcode;
|
||||||
|
@ -862,7 +868,29 @@ String ShaderCompilerGLES3::_dump_node_code(const SL::Node *p_node, int p_level,
|
||||||
} break;
|
} break;
|
||||||
case SL::Node::TYPE_CONSTANT: {
|
case SL::Node::TYPE_CONSTANT: {
|
||||||
SL::ConstantNode *cnode = (SL::ConstantNode *)p_node;
|
SL::ConstantNode *cnode = (SL::ConstantNode *)p_node;
|
||||||
return get_constant_text(cnode->datatype, cnode->values);
|
|
||||||
|
if (cnode->array_size == 0) {
|
||||||
|
return get_constant_text(cnode->datatype, cnode->values);
|
||||||
|
} else {
|
||||||
|
if (cnode->get_datatype() == SL::TYPE_STRUCT) {
|
||||||
|
code += _mkid(cnode->struct_name);
|
||||||
|
} else {
|
||||||
|
code += _typestr(cnode->datatype);
|
||||||
|
}
|
||||||
|
code += "[";
|
||||||
|
code += itos(cnode->array_size);
|
||||||
|
code += "]";
|
||||||
|
code += "(";
|
||||||
|
for (int i = 0; i < cnode->array_size; i++) {
|
||||||
|
if (i > 0) {
|
||||||
|
code += ",";
|
||||||
|
} else {
|
||||||
|
code += "";
|
||||||
|
}
|
||||||
|
code += _dump_node_code(cnode->array_declarations[0].initializer[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
|
||||||
|
}
|
||||||
|
code += ")";
|
||||||
|
}
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case SL::Node::TYPE_OPERATOR: {
|
case SL::Node::TYPE_OPERATOR: {
|
||||||
|
|
|
@ -983,6 +983,9 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, const Map<String
|
||||||
if (r_data_type) {
|
if (r_data_type) {
|
||||||
*r_data_type = shader->constants[p_identifier].type;
|
*r_data_type = shader->constants[p_identifier].type;
|
||||||
}
|
}
|
||||||
|
if (r_array_size) {
|
||||||
|
*r_array_size = shader->constants[p_identifier].array_size;
|
||||||
|
}
|
||||||
if (r_type) {
|
if (r_type) {
|
||||||
*r_type = IDENTIFIER_CONSTANT;
|
*r_type = IDENTIFIER_CONSTANT;
|
||||||
}
|
}
|
||||||
|
@ -2894,7 +2897,7 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltI
|
||||||
} else if (p_node->type == Node::TYPE_ARRAY) {
|
} else if (p_node->type == Node::TYPE_ARRAY) {
|
||||||
ArrayNode *arr = static_cast<ArrayNode *>(p_node);
|
ArrayNode *arr = static_cast<ArrayNode *>(p_node);
|
||||||
|
|
||||||
if (arr->is_const) {
|
if (shader->constants.has(arr->name) || arr->is_const) {
|
||||||
if (r_message) {
|
if (r_message) {
|
||||||
*r_message = RTR("Constants cannot be modified.");
|
*r_message = RTR("Constants cannot be modified.");
|
||||||
}
|
}
|
||||||
|
@ -4749,7 +4752,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
|
||||||
}
|
}
|
||||||
|
|
||||||
DataType type2;
|
DataType type2;
|
||||||
String struct_name2 = "";
|
StringName struct_name2 = "";
|
||||||
|
|
||||||
if (shader->structs.has(tk.text)) {
|
if (shader->structs.has(tk.text)) {
|
||||||
type2 = TYPE_STRUCT;
|
type2 = TYPE_STRUCT;
|
||||||
|
@ -6099,6 +6102,32 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
||||||
constant.type_str = struct_name;
|
constant.type_str = struct_name;
|
||||||
constant.precision = precision;
|
constant.precision = precision;
|
||||||
constant.initializer = nullptr;
|
constant.initializer = nullptr;
|
||||||
|
constant.array_size = 0;
|
||||||
|
|
||||||
|
bool unknown_size = false;
|
||||||
|
|
||||||
|
if (tk.type == TK_BRACKET_OPEN) {
|
||||||
|
if (VisualServer::get_singleton()->is_low_end()) {
|
||||||
|
_set_error("Global const arrays are supported only on high-end platform!");
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
tk = _get_token();
|
||||||
|
if (tk.type == TK_BRACKET_CLOSE) {
|
||||||
|
unknown_size = true;
|
||||||
|
tk = _get_token();
|
||||||
|
} else if (tk.type == TK_INT_CONSTANT && ((int)tk.constant) > 0) {
|
||||||
|
constant.array_size = (int)tk.constant;
|
||||||
|
tk = _get_token();
|
||||||
|
if (tk.type != TK_BRACKET_CLOSE) {
|
||||||
|
_set_error("Expected ']'");
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
tk = _get_token();
|
||||||
|
} else {
|
||||||
|
_set_error("Expected integer constant > 0 or ']'");
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (tk.type == TK_OP_ASSIGN) {
|
if (tk.type == TK_OP_ASSIGN) {
|
||||||
if (!is_constant) {
|
if (!is_constant) {
|
||||||
|
@ -6106,32 +6135,216 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
//variable created with assignment! must parse an expression
|
if (constant.array_size > 0 || unknown_size) {
|
||||||
Node *expr = _parse_and_reduce_expression(nullptr, Map<StringName, BuiltInInfo>());
|
bool full_def = false;
|
||||||
if (!expr) {
|
|
||||||
return ERR_PARSE_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expr->type == Node::TYPE_OPERATOR && ((OperatorNode *)expr)->op == OP_CALL) {
|
ArrayDeclarationNode::Declaration decl;
|
||||||
_set_error("Expected constant expression after '='");
|
decl.name = name;
|
||||||
return ERR_PARSE_ERROR;
|
decl.size = constant.array_size;
|
||||||
}
|
|
||||||
|
|
||||||
constant.initializer = static_cast<ConstantNode *>(expr);
|
tk = _get_token();
|
||||||
|
|
||||||
if (is_struct) {
|
if (tk.type != TK_CURLY_BRACKET_OPEN) {
|
||||||
if (expr->get_datatype_name() != struct_name) {
|
if (unknown_size) {
|
||||||
_set_error("Invalid assignment of '" + (expr->get_datatype() == TYPE_STRUCT ? expr->get_datatype_name() : get_datatype_name(expr->get_datatype())) + "' to '" + struct_name + "'");
|
_set_error("Expected '{'");
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
full_def = true;
|
||||||
|
|
||||||
|
DataPrecision precision2 = PRECISION_DEFAULT;
|
||||||
|
if (is_token_precision(tk.type)) {
|
||||||
|
precision2 = get_token_precision(tk.type);
|
||||||
|
tk = _get_token();
|
||||||
|
if (!is_token_nonvoid_datatype(tk.type)) {
|
||||||
|
_set_error("Expected datatype after precision");
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StringName struct_name2;
|
||||||
|
DataType type2;
|
||||||
|
|
||||||
|
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 ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
type2 = get_token_datatype(tk.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
int array_size2 = 0;
|
||||||
|
tk = _get_token();
|
||||||
|
if (tk.type == TK_BRACKET_OPEN) {
|
||||||
|
TkPos pos2 = _get_tkpos();
|
||||||
|
tk = _get_token();
|
||||||
|
if (tk.type == TK_BRACKET_CLOSE) {
|
||||||
|
array_size2 = constant.array_size;
|
||||||
|
tk = _get_token();
|
||||||
|
} else {
|
||||||
|
_set_tkpos(pos2);
|
||||||
|
|
||||||
|
Node *n = _parse_and_reduce_expression(NULL, Map<StringName, BuiltInInfo>());
|
||||||
|
if (!n || n->type != Node::TYPE_CONSTANT || n->get_datatype() != TYPE_INT) {
|
||||||
|
_set_error("Expected single integer constant > 0");
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_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;
|
||||||
|
} else {
|
||||||
|
tk = _get_token();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_set_error("Expected '[");
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (constant.precision != precision2 || constant.type != type2 || struct_name != struct_name2 || constant.array_size != array_size2) {
|
||||||
|
String error_str = "Cannot convert from '";
|
||||||
|
if (type2 == TYPE_STRUCT) {
|
||||||
|
error_str += struct_name2;
|
||||||
|
} else {
|
||||||
|
if (precision2 != PRECISION_DEFAULT) {
|
||||||
|
error_str += get_precision_name(precision2);
|
||||||
|
error_str += " ";
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
if (precision != PRECISION_DEFAULT) {
|
||||||
|
error_str += get_precision_name(precision);
|
||||||
|
error_str += " ";
|
||||||
|
}
|
||||||
|
error_str += get_datatype_name(type);
|
||||||
|
}
|
||||||
|
error_str += "[";
|
||||||
|
error_str += itos(constant.array_size);
|
||||||
|
error_str += "]'";
|
||||||
|
_set_error(error_str);
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool curly = tk.type == TK_CURLY_BRACKET_OPEN;
|
||||||
|
|
||||||
|
if (unknown_size) {
|
||||||
|
if (!curly) {
|
||||||
|
_set_error("Expected '{'");
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (full_def) {
|
||||||
|
if (curly) {
|
||||||
|
_set_error("Expected '('");
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tk.type == TK_PARENTHESIS_OPEN || curly) { // initialization
|
||||||
|
while (true) {
|
||||||
|
Node *n = _parse_and_reduce_expression(NULL, Map<StringName, BuiltInInfo>());
|
||||||
|
if (!n) {
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n->type == Node::TYPE_OPERATOR && ((OperatorNode *)n)->op == OP_CALL) {
|
||||||
|
_set_error("Expected constant expression");
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (constant.type != n->get_datatype() || n->get_datatype_name() != struct_name) {
|
||||||
|
_set_error("Invalid assignment of '" + (n->get_datatype() == TYPE_STRUCT ? n->get_datatype_name() : get_datatype_name(n->get_datatype())) + "' to '" + (is_struct ? String(struct_name) : get_datatype_name(constant.type)) + "'");
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
tk = _get_token();
|
||||||
|
if (tk.type == TK_COMMA) {
|
||||||
|
decl.initializer.push_back(n);
|
||||||
|
continue;
|
||||||
|
} else if (!curly && tk.type == TK_PARENTHESIS_CLOSE) {
|
||||||
|
decl.initializer.push_back(n);
|
||||||
|
break;
|
||||||
|
} else if (curly && tk.type == TK_CURLY_BRACKET_CLOSE) {
|
||||||
|
decl.initializer.push_back(n);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (curly)
|
||||||
|
_set_error("Expected '}' or ','");
|
||||||
|
else
|
||||||
|
_set_error("Expected ')' or ','");
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (unknown_size) {
|
||||||
|
decl.size = decl.initializer.size();
|
||||||
|
constant.array_size = decl.initializer.size();
|
||||||
|
} else if (decl.initializer.size() != constant.array_size) {
|
||||||
|
_set_error("Array size mismatch");
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ConstantNode *expr = memnew(ConstantNode);
|
||||||
|
|
||||||
|
expr->datatype = constant.type;
|
||||||
|
|
||||||
|
expr->struct_name = constant.type_str;
|
||||||
|
|
||||||
|
expr->array_size = constant.array_size;
|
||||||
|
|
||||||
|
expr->array_declarations.push_back(decl);
|
||||||
|
|
||||||
|
constant.initializer = static_cast<ConstantNode *>(expr);
|
||||||
|
} else {
|
||||||
|
//variable created with assignment! must parse an expression
|
||||||
|
Node *expr = _parse_and_reduce_expression(NULL, Map<StringName, BuiltInInfo>());
|
||||||
|
if (!expr)
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
if (expr->type == Node::TYPE_OPERATOR && ((OperatorNode *)expr)->op == OP_CALL) {
|
||||||
|
_set_error("Expected constant expression after '='");
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
constant.initializer = static_cast<ConstantNode *>(expr);
|
||||||
|
|
||||||
|
if (type != expr->get_datatype() || expr->get_datatype_name() != struct_name) {
|
||||||
|
_set_error("Invalid assignment of '" + (expr->get_datatype() == TYPE_STRUCT ? expr->get_datatype_name() : get_datatype_name(expr->get_datatype())) + "' to '" + (is_struct ? String(struct_name) : get_datatype_name(type)) + "'");
|
||||||
return ERR_PARSE_ERROR;
|
return ERR_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
} else if (type != expr->get_datatype()) {
|
|
||||||
_set_error("Invalid assignment of '" + get_datatype_name(expr->get_datatype()) + "' to '" + get_datatype_name(type) + "'");
|
|
||||||
return ERR_PARSE_ERROR;
|
|
||||||
}
|
}
|
||||||
tk = _get_token();
|
tk = _get_token();
|
||||||
} else {
|
} else {
|
||||||
_set_error("Expected initialization of constant");
|
if (constant.array_size > 0 || unknown_size) {
|
||||||
return ERR_PARSE_ERROR;
|
_set_error("Expected array initialization");
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
} else {
|
||||||
|
_set_error("Expected initialization of constant");
|
||||||
|
return ERR_PARSE_ERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
shader->constants[name] = constant;
|
shader->constants[name] = constant;
|
||||||
|
|
|
@ -441,6 +441,8 @@ public:
|
||||||
|
|
||||||
struct ConstantNode : public Node {
|
struct ConstantNode : public Node {
|
||||||
DataType datatype;
|
DataType datatype;
|
||||||
|
String struct_name = "";
|
||||||
|
int array_size = 0;
|
||||||
|
|
||||||
union Value {
|
union Value {
|
||||||
bool boolean;
|
bool boolean;
|
||||||
|
@ -450,7 +452,9 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
Vector<Value> values;
|
Vector<Value> values;
|
||||||
|
Vector<ArrayDeclarationNode::Declaration> array_declarations;
|
||||||
virtual DataType get_datatype() const { return datatype; }
|
virtual DataType get_datatype() const { return datatype; }
|
||||||
|
virtual String get_datatype_name() const { return struct_name; }
|
||||||
|
|
||||||
ConstantNode() :
|
ConstantNode() :
|
||||||
Node(TYPE_CONSTANT),
|
Node(TYPE_CONSTANT),
|
||||||
|
@ -570,6 +574,7 @@ public:
|
||||||
StringName type_str;
|
StringName type_str;
|
||||||
DataPrecision precision;
|
DataPrecision precision;
|
||||||
ConstantNode *initializer;
|
ConstantNode *initializer;
|
||||||
|
int array_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Function {
|
struct Function {
|
||||||
|
|
Loading…
Reference in a new issue