Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented global const array to shaders #32751

Merged
merged 1 commit into from
Jun 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion servers/rendering/rasterizer_rd/shader_compiler_rd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,11 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
gcode += _typestr(cnode.type);
}
gcode += " " + _mkid(String(cnode.name));
if (cnode.array_size > 0) {
gcode += "[";
gcode += itos(cnode.array_size);
gcode += "]";
}
gcode += "=";
gcode += _dump_node_code(cnode.initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
gcode += ";\n";
Expand Down Expand Up @@ -988,7 +993,29 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
} break;
case SL::Node::TYPE_CONSTANT: {
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;
case SL::Node::TYPE_OPERATOR: {
Expand Down
256 changes: 237 additions & 19 deletions servers/rendering/shader_language.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1014,6 +1014,9 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
if (r_data_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) {
*r_type = IDENTIFIER_CONSTANT;
}
Expand Down Expand Up @@ -3064,7 +3067,7 @@ bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltI
} else if (p_node->type == Node::TYPE_ARRAY) {
ArrayNode *arr = static_cast<ArrayNode *>(p_node);

if (arr->is_const) {
if (shader->constants.has(arr->name) || arr->is_const) {
if (r_message) {
*r_message = RTR("Constants cannot be modified.");
}
Expand Down Expand Up @@ -4976,7 +4979,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const Map<StringName, Bui
}

DataType type2;
String struct_name2 = "";
StringName struct_name2 = "";

if (shader->structs.has(tk.text)) {
type2 = TYPE_STRUCT;
Expand Down Expand Up @@ -6445,38 +6448,253 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
constant.type_str = struct_name;
constant.precision = precision;
constant.initializer = nullptr;
constant.array_size = 0;

if (tk.type == TK_OP_ASSIGN) {
if (!is_constant) {
_set_error("Expected 'const' keyword before constant definition");
bool unknown_size = false;

if (tk.type == TK_BRACKET_OPEN) {
if (RenderingServer::get_singleton()->is_low_end()) {
_set_error("Global const arrays are supported only on high-end platform!");
return ERR_PARSE_ERROR;
}

//variable created with assignment! must parse an expression
Node *expr = _parse_and_reduce_expression(nullptr, Map<StringName, BuiltInInfo>());
if (!expr) {
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 (expr->type == Node::TYPE_OPERATOR && ((OperatorNode *)expr)->op == OP_CALL) {
_set_error("Expected constant expression after '='");
}

if (tk.type == TK_OP_ASSIGN) {
if (!is_constant) {
_set_error("Expected 'const' keyword before constant definition");
return ERR_PARSE_ERROR;
}

constant.initializer = static_cast<ConstantNode *>(expr);
if (constant.array_size > 0 || unknown_size) {
bool full_def = false;

ArrayDeclarationNode::Declaration decl;
decl.name = name;
decl.size = constant.array_size;

if (is_struct) {
if (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 '" + struct_name + "'");
tk = _get_token();

if (tk.type != TK_CURLY_BRACKET_OPEN) {
if (unknown_size) {
_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;
}
} 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();
} else {
_set_error("Expected initialization of constant");
return ERR_PARSE_ERROR;
if (constant.array_size > 0 || unknown_size) {
_set_error("Expected array initialization");
return ERR_PARSE_ERROR;
} else {
_set_error("Expected initialization of constant");
return ERR_PARSE_ERROR;
}
}

shader->constants[name] = constant;
Expand Down
5 changes: 5 additions & 0 deletions servers/rendering/shader_language.h
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,8 @@ class ShaderLanguage {

struct ConstantNode : public Node {
DataType datatype = TYPE_VOID;
String struct_name = "";
int array_size = 0;

union Value {
bool boolean;
Expand All @@ -462,7 +464,9 @@ class ShaderLanguage {
};

Vector<Value> values;
Vector<ArrayDeclarationNode::Declaration> array_declarations;
virtual DataType get_datatype() const { return datatype; }
virtual String get_datatype_name() const { return struct_name; }

ConstantNode() :
Node(TYPE_CONSTANT) {}
Expand Down Expand Up @@ -573,6 +577,7 @@ class ShaderLanguage {
StringName type_str;
DataPrecision precision;
ConstantNode *initializer;
int array_size;
};

struct Function {
Expand Down