Skip to content

Commit

Permalink
Merge pull request #32751 from Chaosus/shader_const_array
Browse files Browse the repository at this point in the history
Implemented global const array to shaders
  • Loading branch information
Chaosus authored Jun 19, 2020
2 parents a8d302b + 636a9d9 commit c857d77
Show file tree
Hide file tree
Showing 3 changed files with 270 additions and 20 deletions.
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

0 comments on commit c857d77

Please sign in to comment.