Add basic support to evaluate operator value in shader language

This commit is contained in:
Yuri Rubinsky 2024-07-01 16:39:49 +03:00 committed by Chaosus
parent d0dc3896ad
commit af92fdb0ac
5 changed files with 540 additions and 121 deletions

View File

@ -348,7 +348,7 @@ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, int p_
}
}
_FORCE_INLINE_ static void _fill_std140_ubo_value(ShaderLanguage::DataType type, const Vector<ShaderLanguage::ConstantNode::Value> &value, uint8_t *data) {
_FORCE_INLINE_ static void _fill_std140_ubo_value(ShaderLanguage::DataType type, const Vector<ShaderLanguage::Scalar> &value, uint8_t *data) {
switch (type) {
case ShaderLanguage::TYPE_BOOL: {
uint32_t *gui = (uint32_t *)data;
@ -572,7 +572,7 @@ void ShaderData::set_default_texture_parameter(const StringName &p_name, RID p_t
Variant ShaderData::get_default_parameter(const StringName &p_parameter) const {
if (uniforms.has(p_parameter)) {
ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
Vector<ShaderLanguage::Scalar> default_value = uniform.default_value;
return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
}
return Variant();

View File

@ -342,7 +342,7 @@ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, int p_
}
}
_FORCE_INLINE_ static void _fill_std140_ubo_value(ShaderLanguage::DataType type, const Vector<ShaderLanguage::ConstantNode::Value> &value, uint8_t *data) {
_FORCE_INLINE_ static void _fill_std140_ubo_value(ShaderLanguage::DataType type, const Vector<ShaderLanguage::Scalar> &value, uint8_t *data) {
switch (type) {
case ShaderLanguage::TYPE_BOOL: {
uint32_t *gui = (uint32_t *)data;
@ -566,7 +566,7 @@ void MaterialStorage::ShaderData::set_default_texture_parameter(const StringName
Variant MaterialStorage::ShaderData::get_default_parameter(const StringName &p_parameter) const {
if (uniforms.has(p_parameter)) {
ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
Vector<ShaderLanguage::Scalar> default_value = uniform.default_value;
return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
}
return Variant();

View File

@ -185,7 +185,7 @@ static String f2sp0(float p_float) {
return num;
}
static String get_constant_text(SL::DataType p_type, const Vector<SL::ConstantNode::Value> &p_values) {
static String get_constant_text(SL::DataType p_type, const Vector<SL::Scalar> &p_values) {
switch (p_type) {
case SL::TYPE_BOOL:
return p_values[0].boolean ? "true" : "false";

View File

@ -1362,7 +1362,7 @@ void ShaderLanguage::_parse_used_identifier(const StringName &p_identifier, Iden
}
#endif // DEBUG_ENABLED
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) {
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, Vector<Scalar> *r_constant_values) {
if (is_shader_inc) {
for (int i = 0; i < RenderingServer::SHADER_MAX; i++) {
for (const KeyValue<StringName, FunctionInfo> &E : ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(i))) {
@ -1424,8 +1424,8 @@ 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;
if (r_constant_values && !p_block->variables[p_identifier].values.is_empty()) {
*r_constant_values = p_block->variables[p_identifier].values;
}
if (r_type) {
*r_type = IDENTIFIER_LOCAL_VAR;
@ -1507,13 +1507,9 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
if (r_struct_name) {
*r_struct_name = shader->constants[p_identifier].struct_name;
}
if (r_constant_value) {
if (shader->constants[p_identifier].initializer && shader->constants[p_identifier].initializer->type == Node::NODE_TYPE_CONSTANT) {
ConstantNode *cnode = static_cast<ConstantNode *>(shader->constants[p_identifier].initializer);
if (cnode->values.size() == 1) {
*r_constant_value = cnode->values[0];
}
if (r_constant_values) {
if (shader->constants[p_identifier].initializer && !shader->constants[p_identifier].initializer->get_values().is_empty()) {
*r_constant_values = shader->constants[p_identifier].initializer->get_values();
}
}
if (r_type) {
@ -1544,7 +1540,7 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
return false;
}
bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type, int *r_ret_size) {
bool ShaderLanguage::_validate_operator(const BlockNode *p_block, OperatorNode *p_op, DataType *r_ret_type, int *r_ret_size) {
bool valid = false;
DataType ret_type = TYPE_VOID;
int ret_size = 0;
@ -2007,9 +2003,384 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type
if (r_ret_size) {
*r_ret_size = ret_size;
}
if (valid && (!p_block || p_block->use_op_eval)) {
// Need to be placed here and not in the `_reduce_expression` because otherwise expressions like `1 + 2 / 2` will not work correctly.
valid = _eval_operator(p_block, p_op);
}
return valid;
}
Vector<ShaderLanguage::Scalar> ShaderLanguage::_get_node_values(const BlockNode *p_block, Node *p_node) {
Vector<Scalar> result;
switch (p_node->type) {
case Node::NODE_TYPE_VARIABLE: {
_find_identifier(p_block, false, FunctionInfo(), static_cast<VariableNode *>(p_node)->name, nullptr, nullptr, nullptr, nullptr, nullptr, &result);
} break;
default: {
result = p_node->get_values();
} break;
}
return result;
}
bool ShaderLanguage::_eval_operator(const BlockNode *p_block, OperatorNode *p_op) {
bool is_valid = true;
switch (p_op->op) {
case OP_EQUAL:
case OP_NOT_EQUAL:
case OP_LESS:
case OP_LESS_EQUAL:
case OP_GREATER:
case OP_GREATER_EQUAL:
case OP_AND:
case OP_OR:
case OP_ADD:
case OP_SUB:
case OP_MUL:
case OP_DIV:
case OP_MOD:
case OP_SHIFT_LEFT:
case OP_SHIFT_RIGHT:
case OP_BIT_AND:
case OP_BIT_OR:
case OP_BIT_XOR: {
DataType a = p_op->arguments[0]->get_datatype();
DataType b = p_op->arguments[1]->get_datatype();
bool is_op_vec_transform = false;
if (p_op->op == OP_MUL) {
DataType ta = a;
DataType tb = b;
if (ta > tb) {
SWAP(ta, tb);
}
if (ta == TYPE_VEC2 && tb == TYPE_MAT2) {
is_op_vec_transform = true;
} else if (ta == TYPE_VEC3 && tb == TYPE_MAT3) {
is_op_vec_transform = true;
} else if (ta == TYPE_VEC4 && tb == TYPE_MAT4) {
is_op_vec_transform = true;
}
}
Vector<Scalar> va = _get_node_values(p_block, p_op->arguments[0]);
Vector<Scalar> vb = _get_node_values(p_block, p_op->arguments[1]);
if (is_op_vec_transform) {
p_op->values = _eval_vector_transform(va, vb, a, b, p_op->get_datatype());
} else {
p_op->values = _eval_vector(va, vb, a, b, p_op->get_datatype(), p_op->op, is_valid);
}
} break;
case OP_NOT:
case OP_NEGATE:
case OP_BIT_INVERT: {
p_op->values = _eval_unary_vector(_get_node_values(p_block, p_op->arguments[0]), p_op->get_datatype(), p_op->op);
} break;
default: {
} break;
}
return is_valid;
}
ShaderLanguage::Scalar ShaderLanguage::_eval_unary_scalar(const Scalar &p_a, Operator p_op, DataType p_ret_type) {
Scalar scalar;
switch (p_op) {
case OP_NOT: {
scalar.boolean = !p_a.boolean;
} break;
case OP_NEGATE: {
if (p_ret_type >= TYPE_INT && p_ret_type <= TYPE_IVEC4) {
scalar.sint = -p_a.sint;
} else if (p_ret_type >= TYPE_UINT && p_ret_type <= TYPE_UVEC4) {
// Intentionally wrap the unsigned int value, because GLSL does.
scalar.uint = 0 - p_a.uint;
} else { // float types
scalar.real = -scalar.real;
}
} break;
case OP_BIT_INVERT: {
if (p_ret_type >= TYPE_INT && p_ret_type <= TYPE_IVEC4) {
scalar.sint = ~p_a.sint;
} else { // uint types
scalar.uint = ~p_a.uint;
}
} break;
default: {
} break;
}
return scalar;
}
ShaderLanguage::Scalar ShaderLanguage::_eval_scalar(const Scalar &p_a, const Scalar &p_b, Operator p_op, DataType p_ret_type, bool &r_is_valid) {
Scalar scalar;
switch (p_op) {
case OP_EQUAL: {
scalar.boolean = p_a.boolean == p_b.boolean;
} break;
case OP_NOT_EQUAL: {
scalar.boolean = p_a.boolean != p_b.boolean;
} break;
case OP_LESS: {
if (p_ret_type == TYPE_INT) {
scalar.boolean = p_a.sint < p_b.sint;
} else if (p_ret_type == TYPE_UINT) {
scalar.boolean = p_a.uint < p_b.uint;
} else { // float type
scalar.boolean = p_a.real < p_b.real;
}
} break;
case OP_LESS_EQUAL: {
if (p_ret_type == TYPE_INT) {
scalar.boolean = p_a.sint <= p_b.sint;
} else if (p_ret_type == TYPE_UINT) {
scalar.boolean = p_a.uint <= p_b.uint;
} else { // float type
scalar.boolean = p_a.real <= p_b.real;
}
} break;
case OP_GREATER: {
if (p_ret_type == TYPE_INT) {
scalar.boolean = p_a.sint > p_b.sint;
} else if (p_ret_type == TYPE_UINT) {
scalar.boolean = p_a.uint > p_b.uint;
} else { // float type
scalar.boolean = p_a.real > p_b.real;
}
} break;
case OP_GREATER_EQUAL: {
if (p_ret_type == TYPE_INT) {
scalar.boolean = p_a.sint >= p_b.sint;
} else if (p_ret_type == TYPE_UINT) {
scalar.boolean = p_a.uint >= p_b.uint;
} else { // float type
scalar.boolean = p_a.real >= p_b.real;
}
} break;
case OP_AND: {
scalar.boolean = p_a.boolean && p_b.boolean;
} break;
case OP_OR: {
scalar.boolean = p_a.boolean || p_b.boolean;
} break;
case OP_ADD: {
if (p_ret_type >= TYPE_INT && p_ret_type <= TYPE_IVEC4) {
scalar.sint = p_a.sint + p_b.sint;
} else if (p_ret_type >= TYPE_UINT && p_ret_type <= TYPE_UVEC4) {
scalar.uint = p_a.uint + p_b.uint;
} else { // float + matrix types
scalar.real = p_a.real + p_b.real;
}
} break;
case OP_SUB: {
if (p_ret_type >= TYPE_INT && p_ret_type <= TYPE_IVEC4) {
scalar.sint = p_a.sint - p_b.sint;
} else if (p_ret_type >= TYPE_UINT && p_ret_type <= TYPE_UVEC4) {
scalar.uint = p_a.uint - p_b.uint;
} else { // float + matrix types
scalar.real = p_a.real - p_b.real;
}
} break;
case OP_MUL: {
if (p_ret_type >= TYPE_INT && p_ret_type <= TYPE_IVEC4) {
scalar.sint = p_a.sint * p_b.sint;
} else if (p_ret_type >= TYPE_UINT && p_ret_type <= TYPE_UVEC4) {
scalar.uint = p_a.uint * p_b.uint;
} else { // float + matrix types
scalar.real = p_a.real * p_b.real;
}
} break;
case OP_DIV: {
if (p_ret_type >= TYPE_INT && p_ret_type <= TYPE_IVEC4) {
if (p_b.sint == 0) {
_set_error(RTR("Division by zero error."));
r_is_valid = false;
break;
}
scalar.sint = p_a.sint / p_b.sint;
} else if (p_ret_type == TYPE_UINT && p_ret_type <= TYPE_UVEC4) {
if (p_b.uint == 0U) {
_set_error(RTR("Division by zero error."));
r_is_valid = false;
break;
}
scalar.uint = p_a.uint / p_b.uint;
} else { // float + matrix types
scalar.real = p_a.real / p_b.real;
}
} break;
case OP_MOD: {
if (p_ret_type >= TYPE_INT && p_ret_type <= TYPE_IVEC4) {
if (p_b.sint == 0) {
_set_error(RTR("Modulo by zero error."));
r_is_valid = false;
break;
}
scalar.sint = p_a.sint % p_b.sint;
} else { // uint types
if (p_b.uint == 0U) {
_set_error(RTR("Modulo by zero error."));
r_is_valid = false;
break;
}
scalar.uint = p_a.uint % p_b.uint;
}
} break;
case OP_SHIFT_LEFT: {
if (p_ret_type >= TYPE_INT && p_ret_type <= TYPE_IVEC4) {
scalar.sint = p_a.sint << p_b.sint;
} else { // uint types
scalar.uint = p_a.uint << p_b.uint;
}
} break;
case OP_SHIFT_RIGHT: {
if (p_ret_type >= TYPE_INT && p_ret_type <= TYPE_IVEC4) {
scalar.sint = p_a.sint >> p_b.sint;
} else { // uint types
scalar.uint = p_a.uint >> p_b.uint;
}
} break;
case OP_BIT_AND: {
if (p_ret_type >= TYPE_INT && p_ret_type <= TYPE_IVEC4) {
scalar.sint = p_a.sint & p_b.sint;
} else { // uint types
scalar.uint = p_a.uint & p_b.uint;
}
} break;
case OP_BIT_OR: {
if (p_ret_type >= TYPE_INT && p_ret_type <= TYPE_IVEC4) {
scalar.sint = p_a.sint | p_b.sint;
} else { // uint types
scalar.uint = p_a.uint | p_b.uint;
}
} break;
case OP_BIT_XOR: {
if (p_ret_type >= TYPE_INT && p_ret_type <= TYPE_IVEC4) {
scalar.sint = p_a.sint ^ p_b.sint;
} else { // uint types
scalar.uint = p_a.uint ^ p_b.uint;
}
} break;
default: {
} break;
}
return scalar;
}
Vector<ShaderLanguage::Scalar> ShaderLanguage::_eval_unary_vector(const Vector<Scalar> &p_va, DataType p_ret_type, Operator p_op) {
uint32_t size = get_datatype_component_count(p_ret_type);
if (p_va.size() != p_ret_type) {
return Vector<Scalar>(); // Non-evaluable values should not be parsed further.
}
Vector<Scalar> value;
value.resize(size);
Scalar *w = value.ptrw();
for (uint32_t i = 0U; i < size; i++) {
w[i] = _eval_unary_scalar(p_va[i], p_op, p_ret_type);
}
return value;
}
Vector<ShaderLanguage::Scalar> ShaderLanguage::_eval_vector(const Vector<Scalar> &p_va, const Vector<Scalar> &p_vb, DataType p_left_type, DataType p_right_type, DataType p_ret_type, Operator p_op, bool &r_is_valid) {
uint32_t left_size = get_datatype_component_count(p_left_type);
uint32_t right_size = get_datatype_component_count(p_right_type);
if (p_va.size() != left_size || p_vb.size() != right_size) {
return Vector<Scalar>(); // Non-evaluable values should not be parsed further.
}
uint32_t ret_size = get_datatype_component_count(p_ret_type);
Vector<Scalar> value;
value.resize(ret_size);
Scalar *w = value.ptrw();
for (uint32_t i = 0U; i < ret_size; i++) {
w[i] = _eval_scalar(p_va[MIN(i, left_size - 1)], p_vb[MIN(i, right_size - 1)], p_op, p_ret_type, r_is_valid);
if (!r_is_valid) {
return value;
}
}
return value;
}
Vector<ShaderLanguage::Scalar> ShaderLanguage::_eval_vector_transform(const Vector<Scalar> &p_va, const Vector<Scalar> &p_vb, DataType p_left_type, DataType p_right_type, DataType p_ret_type) {
uint32_t left_size = get_datatype_component_count(p_left_type);
uint32_t right_size = get_datatype_component_count(p_right_type);
if (p_va.size() != left_size || p_vb.size() != right_size) {
return Vector<Scalar>(); // Non-evaluable values should not be parsed further.
}
uint32_t ret_size = get_datatype_component_count(p_ret_type);
Vector<Scalar> value;
value.resize_zeroed(ret_size);
Scalar *w = value.ptrw();
switch (p_ret_type) {
case TYPE_VEC2: {
if (left_size == 2) { // v * m
Vector2 v = Vector2(p_va[0].real, p_va[1].real);
w[0].real = (p_vb[0].real * v.x + p_vb[1].real * v.y);
w[1].real = (p_vb[2].real * v.x + p_vb[3].real * v.y);
} else { // m * v
Vector2 v = Vector2(p_vb[0].real, p_vb[1].real);
w[0].real = (p_va[0].real * v.x + p_va[2].real * v.y);
w[1].real = (p_va[1].real * v.x + p_va[3].real * v.y);
}
} break;
case TYPE_VEC3: {
if (left_size == 3) { // v * m
Vector3 v = Vector3(p_va[0].real, p_va[1].real, p_va[2].real);
w[0].real = (p_vb[0].real * v.x + p_vb[1].real * v.y + p_vb[2].real * v.z);
w[1].real = (p_vb[3].real * v.x + p_vb[4].real * v.y + p_vb[5].real * v.z);
w[2].real = (p_vb[6].real * v.x + p_vb[7].real * v.y + p_vb[8].real * v.z);
} else { // m * v
Vector3 v = Vector3(p_vb[0].real, p_vb[1].real, p_vb[2].real);
w[0].real = (p_va[0].real * v.x + p_va[3].real * v.y + p_va[6].real * v.z);
w[1].real = (p_va[1].real * v.x + p_va[4].real * v.y + p_va[7].real * v.z);
w[2].real = (p_va[2].real * v.x + p_va[5].real * v.y + p_va[8].real * v.z);
}
} break;
case TYPE_VEC4: {
if (left_size == 4) { // v * m
Vector4 v = Vector4(p_va[0].real, p_va[1].real, p_va[2].real, p_va[3].real);
w[0].real = (p_vb[0].real * v.x + p_vb[1].real * v.y + p_vb[2].real * v.z + p_vb[3].real * v.w);
w[1].real = (p_vb[4].real * v.x + p_vb[5].real * v.y + p_vb[6].real * v.z + p_vb[7].real * v.w);
w[2].real = (p_vb[8].real * v.x + p_vb[9].real * v.y + p_vb[10].real * v.z + p_vb[11].real * v.w);
w[3].real = (p_vb[12].real * v.x + p_vb[13].real * v.y + p_vb[14].real * v.z + p_vb[15].real * v.w);
} else { // m * v
Vector4 v = Vector4(p_vb[0].real, p_vb[1].real, p_vb[2].real, p_vb[3].real);
w[0].real = (p_vb[0].real * v.x + p_vb[4].real * v.y + p_vb[8].real * v.z + p_vb[12].real * v.w);
w[1].real = (p_vb[1].real * v.x + p_vb[5].real * v.y + p_vb[9].real * v.z + p_vb[13].real * v.w);
w[2].real = (p_vb[2].real * v.x + p_vb[6].real * v.y + p_vb[10].real * v.z + p_vb[14].real * v.w);
w[3].real = (p_vb[3].real * v.x + p_vb[7].real * v.y + p_vb[11].real * v.z + p_vb[15].real * v.w);
}
} break;
default: {
} break;
}
return value;
}
const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = {
// Constructors.
@ -3271,34 +3642,15 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
int max = builtin_func_const_args[constarg_idx].max;
bool error = false;
if (p_func->arguments[arg]->type == Node::NODE_TYPE_VARIABLE) {
const VariableNode *vn = static_cast<VariableNode *>(p_func->arguments[arg]);
bool is_const = false;
ConstantNode::Value value;
value.sint = -1;
_find_identifier(p_block, false, p_function_info, vn->name, nullptr, nullptr, &is_const, nullptr, nullptr, &value);
if (!is_const || value.sint < min || value.sint > max) {
error = true;
}
} else {
if (p_func->arguments[arg]->type == Node::NODE_TYPE_CONSTANT) {
const ConstantNode *cn = static_cast<ConstantNode *>(p_func->arguments[arg]);
if (cn->get_datatype() == TYPE_INT && cn->values.size() == 1) {
int value = cn->values[0].sint;
if (value < min || value > max) {
Vector<Scalar> values = _get_node_values(p_block, p_func->arguments[arg]);
if (p_func->arguments[arg]->get_datatype() == TYPE_INT && !values.is_empty()) {
if (values[0].sint < min || values[0].sint > max) {
error = true;
}
} else {
error = true;
}
} else {
error = true;
}
}
if (error) {
_set_error(vformat(RTR("Expected integer constant within [%d..%d] range."), min, max));
return false;
@ -3760,7 +4112,7 @@ bool ShaderLanguage::is_token_hint(TokenType p_type) {
return int(p_type) > int(TK_RENDER_MODE) && int(p_type) < int(TK_SHADER_TYPE);
}
bool ShaderLanguage::convert_constant(ConstantNode *p_constant, DataType p_to_type, ConstantNode::Value *p_value) {
bool ShaderLanguage::convert_constant(ConstantNode *p_constant, DataType p_to_type, Scalar *p_value) {
if (p_constant->datatype == p_to_type) {
if (p_value) {
for (int i = 0; i < p_constant->values.size(); i++) {
@ -3828,7 +4180,7 @@ bool ShaderLanguage::is_sampler_type(DataType p_type) {
return p_type > TYPE_MAT4 && p_type < TYPE_STRUCT;
}
Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, int p_array_size, ShaderLanguage::ShaderNode::Uniform::Hint p_hint) {
Variant ShaderLanguage::constant_value_to_variant(const Vector<Scalar> &p_value, DataType p_type, int p_array_size, ShaderLanguage::ShaderNode::Uniform::Hint p_hint) {
int array_size = p_array_size;
if (p_value.size() > 0) {
@ -4437,6 +4789,52 @@ uint32_t ShaderLanguage::get_datatype_size(ShaderLanguage::DataType p_type) {
ERR_FAIL_V(0);
}
uint32_t ShaderLanguage::get_datatype_component_count(ShaderLanguage::DataType p_type) {
switch (p_type) {
case TYPE_BOOL:
return 1U;
case TYPE_BVEC2:
return 2U;
case TYPE_BVEC3:
return 3U;
case TYPE_BVEC4:
return 4U;
case TYPE_INT:
return 1U;
case TYPE_IVEC2:
return 2U;
case TYPE_IVEC3:
return 3U;
case TYPE_IVEC4:
return 4U;
case TYPE_UINT:
return 1U;
case TYPE_UVEC2:
return 2U;
case TYPE_UVEC3:
return 3U;
case TYPE_UVEC4:
return 4U;
case TYPE_FLOAT:
return 1U;
case TYPE_VEC2:
return 2U;
case TYPE_VEC3:
return 3U;
case TYPE_VEC4:
return 4U;
case TYPE_MAT2:
return 4U;
case TYPE_MAT3:
return 9U;
case TYPE_MAT4:
return 16U;
default:
break;
}
return 0U;
}
void ShaderLanguage::get_keyword_list(List<String> *r_keywords) {
HashSet<String> kws;
@ -4929,46 +5327,31 @@ Error ShaderLanguage::_parse_array_size(BlockNode *p_block, const FunctionInfo &
*r_unknown_size = true;
}
} else {
int array_size = 0;
if (!tk.is_integer_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::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);
int array_size = 0;
Node *expr = _parse_and_reduce_expression(p_block, p_function_info);
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;
if (expr) {
Vector<Scalar> values = _get_node_values(p_block, expr);
if (!values.is_empty()) {
switch (expr->get_datatype()) {
case TYPE_INT: {
array_size = values[0].sint;
} break;
case TYPE_UINT: {
array_size = (int)values[0].uint;
} break;
default: {
} break;
}
}
}
}
} else if (n->type == Node::NODE_TYPE_OPERATOR) {
_set_error(vformat(RTR("Array size expressions are not supported.")));
return ERR_PARSE_ERROR;
}
if (r_size_expression != nullptr) {
*r_size_expression = n;
*r_size_expression = expr;
}
}
} else if (((int)tk.constant) > 0) {
array_size = (uint32_t)tk.constant;
}
if (array_size <= 0) {
_set_error(RTR("Expected a positive integer constant."));
@ -5064,7 +5447,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_bloc
idx++;
}
if (!auto_size && !undefined_size && an->initializer.size() != array_size) {
_set_error(RTR("Array size mismatch."));
_set_error(vformat(RTR("Array size mismatch. Expected %d elements (found %d)."), array_size, an->initializer.size()));
return nullptr;
}
} else {
@ -5185,7 +5568,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_bloc
}
}
if (an->initializer.size() != p_array_size) {
_set_error(RTR("Array size mismatch."));
_set_error(vformat(RTR("Array size mismatch. Expected %d elements (found %d)."), p_array_size, an->initializer.size()));
return nullptr;
}
} else {
@ -5230,7 +5613,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
} else if (tk.type == TK_FLOAT_CONSTANT) {
ConstantNode *constant = alloc_node<ConstantNode>();
ConstantNode::Value v;
Scalar v;
v.real = tk.constant;
constant->values.push_back(v);
constant->datatype = TYPE_FLOAT;
@ -5238,7 +5621,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
} else if (tk.type == TK_INT_CONSTANT) {
ConstantNode *constant = alloc_node<ConstantNode>();
ConstantNode::Value v;
Scalar v;
v.sint = tk.constant;
constant->values.push_back(v);
constant->datatype = TYPE_INT;
@ -5246,7 +5629,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
} else if (tk.type == TK_UINT_CONSTANT) {
ConstantNode *constant = alloc_node<ConstantNode>();
ConstantNode::Value v;
Scalar v;
v.uint = tk.constant;
constant->values.push_back(v);
constant->datatype = TYPE_UINT;
@ -5255,7 +5638,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
} else if (tk.type == TK_TRUE) {
//handle true constant
ConstantNode *constant = alloc_node<ConstantNode>();
ConstantNode::Value v;
Scalar v;
v.boolean = true;
constant->values.push_back(v);
constant->datatype = TYPE_BOOL;
@ -5264,7 +5647,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
} else if (tk.type == TK_FALSE) {
//handle false constant
ConstantNode *constant = alloc_node<ConstantNode>();
ConstantNode::Value v;
Scalar v;
v.boolean = false;
constant->values.push_back(v);
constant->datatype = TYPE_BOOL;
@ -6527,7 +6910,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
op->op = tk.type == TK_OP_DECREMENT ? OP_POST_DECREMENT : OP_POST_INCREMENT;
op->arguments.push_back(expr);
if (!_validate_operator(op, &op->return_cache, &op->return_array_size)) {
if (!_validate_operator(p_block, op, &op->return_cache, &op->return_array_size)) {
_set_error(RTR("Invalid base type for increment/decrement operator."));
return nullptr;
}
@ -6876,7 +7259,11 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
expression.write[i].is_op = false;
expression.write[i].node = op;
if (!_validate_operator(op, &op->return_cache, &op->return_array_size)) {
if (!_validate_operator(p_block, op, &op->return_cache, &op->return_array_size)) {
if (error_set) {
return nullptr;
}
String at;
for (int j = 0; j < op->arguments.size(); j++) {
if (j > 0) {
@ -6914,7 +7301,11 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
expression.write[next_op - 1].is_op = false;
expression.write[next_op - 1].node = op;
if (!_validate_operator(op, &op->return_cache, &op->return_array_size)) {
if (!_validate_operator(p_block, op, &op->return_cache, &op->return_array_size)) {
if (error_set) {
return nullptr;
}
String at;
for (int i = 0; i < op->arguments.size(); i++) {
if (i > 0) {
@ -6950,6 +7341,11 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
if (_is_operator_assign(op->op)) {
if (p_block && expression[next_op - 1].node->type == Node::NODE_TYPE_VARIABLE) {
VariableNode *vn = static_cast<VariableNode *>(expression[next_op - 1].node);
p_block->use_op_eval = vn->is_const;
}
String assign_message;
if (!_validate_assign(expression[next_op - 1].node, p_function_info, &assign_message)) {
_set_error(assign_message);
@ -6972,7 +7368,11 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
//replace all 3 nodes by this operator and make it an expression
if (!_validate_operator(op, &op->return_cache, &op->return_array_size)) {
if (!_validate_operator(p_block, op, &op->return_cache, &op->return_array_size)) {
if (error_set) {
return nullptr;
}
String at;
for (int i = 0; i < op->arguments.size(); i++) {
if (i > 0) {
@ -6998,6 +7398,10 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
}
if (p_block) {
p_block->use_op_eval = true;
}
if (p_previous_expression_info != nullptr) {
p_previous_expression_info->expression->push_back(expression[0]);
}
@ -7020,7 +7424,7 @@ ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha
DataType base = get_scalar_type(type);
int cardinality = get_cardinality(type);
Vector<ConstantNode::Value> values;
Vector<Scalar> values;
for (int i = 1; i < op->arguments.size(); i++) {
op->arguments.write[i] = _reduce_expression(p_block, op->arguments[i]);
@ -7032,7 +7436,7 @@ ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha
values.push_back(cn->values[j]);
}
} else if (get_scalar_type(cn->datatype) == cn->datatype) {
ConstantNode::Value v;
Scalar v;
if (!convert_constant(cn, base, &v)) {
return p_node;
}
@ -7048,8 +7452,8 @@ ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha
if (values.size() == 1) {
if (type >= TYPE_MAT2 && type <= TYPE_MAT4) {
ConstantNode::Value value = values[0];
ConstantNode::Value zero;
Scalar value = values[0];
Scalar zero;
zero.real = 0.0f;
int size = 2 + (type - TYPE_MAT2);
@ -7060,7 +7464,7 @@ ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha
}
}
} else {
ConstantNode::Value value = values[0];
Scalar value = values[0];
for (int i = 1; i < cardinality; i++) {
values.push_back(value);
}
@ -7081,10 +7485,10 @@ ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha
DataType base = get_scalar_type(cn->datatype);
Vector<ConstantNode::Value> values;
Vector<Scalar> values;
for (int i = 0; i < cn->values.size(); i++) {
ConstantNode::Value nv;
Scalar nv;
switch (base) {
case TYPE_BOOL: {
nv.boolean = !cn->values[i].boolean;
@ -7515,7 +7919,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
decl.size = decl.initializer.size();
var.array_size = decl.initializer.size();
} else if (decl.initializer.size() != var.array_size) {
_set_error(RTR("Array size mismatch."));
_set_error(vformat(RTR("Array size mismatch. Expected %d elements (found %d)."), var.array_size, decl.initializer.size()));
return ERR_PARSE_ERROR;
}
tk = _get_token();
@ -7537,7 +7941,9 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
array_size = var.array_size;
} else if (tk.type == TK_OP_ASSIGN) {
//variable created with assignment! must parse an expression
p_block->use_op_eval = is_const;
// Variable created with assignment! Must parse an expression.
Node *n = _parse_and_reduce_expression(p_block, p_function_info);
if (!n) {
return ERR_PARSE_ERROR;
@ -7552,11 +7958,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
}
}
if (n->type == Node::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 (is_const) {
var.values = n->get_values();
}
if (!_compare_datatypes(var.type, var.struct_name, var.array_size, n->get_datatype(), n->get_datatype_name(), n->get_array_size())) {
@ -7734,13 +8137,13 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
if (!vn) {
return ERR_PARSE_ERROR;
}
ConstantNode::Value v;
Vector<Scalar> v = { Scalar() };
_find_identifier(p_block, false, p_function_info, vn->name, nullptr, nullptr, nullptr, nullptr, nullptr, &v);
if (constants.has(v.sint)) {
_set_error(vformat(RTR("Duplicated case label: %d."), v.sint));
if (constants.has(v[0].sint)) {
_set_error(vformat(RTR("Duplicated case label: %d."), v[0].sint));
return ERR_PARSE_ERROR;
}
constants.insert(v.sint);
constants.insert(v[0].sint);
}
} else if (flow->flow_op == FLOW_OP_DEFAULT) {
continue;
@ -7801,7 +8204,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
vn->name = tk.text;
n = vn;
} else {
ConstantNode::Value v;
Scalar v;
if (tk.type == TK_UINT_CONSTANT) {
v.uint = (uint32_t)tk.constant;
} else {
@ -9678,7 +10081,7 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
decl.size = decl.initializer.size();
constant.array_size = decl.initializer.size();
} else if (decl.initializer.size() != constant.array_size) {
_set_error(RTR("Array size mismatch."));
_set_error(vformat(RTR("Array size mismatch. Expected %d elements (found %d)."), constant.array_size, decl.initializer.size()));
return ERR_PARSE_ERROR;
}
} else {

View File

@ -355,6 +355,13 @@ public:
}
};
union Scalar {
bool boolean = false;
float real;
int32_t sint;
uint32_t uint;
};
struct Node {
Node *next = nullptr;
@ -379,6 +386,7 @@ public:
virtual String get_datatype_name() const { return ""; }
virtual int get_array_size() const { return 0; }
virtual bool is_indexed() const { return false; }
virtual Vector<Scalar> get_values() const { return Vector<Scalar>(); }
Node(Type t) :
type(t) {}
@ -402,11 +410,13 @@ public:
Operator op = OP_EQUAL;
StringName struct_name;
Vector<Node *> arguments;
Vector<Scalar> values;
virtual DataType get_datatype() const override { return return_cache; }
virtual String get_datatype_name() const override { return String(struct_name); }
virtual int get_array_size() const override { return return_array_size; }
virtual bool is_indexed() const override { return op == OP_INDEX; }
virtual Vector<Scalar> get_values() const override { return values; }
OperatorNode() :
Node(NODE_TYPE_OPERATOR) {}
@ -485,19 +495,15 @@ public:
String struct_name = "";
int array_size = 0;
union Value {
bool boolean = false;
float real;
int32_t sint;
uint32_t uint;
};
Vector<Value> values;
Vector<Scalar> values;
Vector<VariableDeclarationNode::Declaration> array_declarations;
virtual DataType get_datatype() const override { return datatype; }
virtual String get_datatype_name() const override { return struct_name; }
virtual int get_array_size() const override { return array_size; }
virtual Vector<Scalar> get_values() const override {
return values;
}
ConstantNode() :
Node(NODE_TYPE_CONSTANT) {}
@ -529,13 +535,14 @@ public:
int line; //for completion
int array_size;
bool is_const;
ConstantNode::Value value;
Vector<Scalar> values;
};
HashMap<StringName, Variable> variables;
List<Node *> statements;
bool single_statement = false;
bool use_comma_between_statements = false;
bool use_op_eval = true;
BlockNode() :
Node(NODE_TYPE_BLOCK) {}
@ -657,7 +664,7 @@ public:
DataType type = TYPE_VOID;
DataPrecision precision = PRECISION_DEFAULT;
int array_size = 0;
Vector<ConstantNode::Value> default_value;
Vector<Scalar> default_value;
Scope scope = SCOPE_LOCAL;
Hint hint = HINT_NONE;
bool use_color = false;
@ -803,15 +810,16 @@ public:
static bool is_token_operator_assign(TokenType p_type);
static bool is_token_hint(TokenType p_type);
static bool convert_constant(ConstantNode *p_constant, DataType p_to_type, ConstantNode::Value *p_value = nullptr);
static bool convert_constant(ConstantNode *p_constant, DataType p_to_type, Scalar *p_value = nullptr);
static DataType get_scalar_type(DataType p_type);
static int get_cardinality(DataType p_type);
static bool is_scalar_type(DataType p_type);
static bool is_float_type(DataType p_type);
static bool is_sampler_type(DataType p_type);
static Variant constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, int p_array_size, ShaderLanguage::ShaderNode::Uniform::Hint p_hint = ShaderLanguage::ShaderNode::Uniform::HINT_NONE);
static Variant constant_value_to_variant(const Vector<Scalar> &p_value, DataType p_type, int p_array_size, ShaderLanguage::ShaderNode::Uniform::Hint p_hint = ShaderLanguage::ShaderNode::Uniform::HINT_NONE);
static PropertyInfo uniform_to_property_info(const ShaderNode::Uniform &p_uniform);
static uint32_t get_datatype_size(DataType p_type);
static uint32_t get_datatype_component_count(DataType p_type);
static void get_keyword_list(List<String> *r_keywords);
static bool is_control_flow_keyword(String p_keyword);
@ -1070,13 +1078,21 @@ private:
IdentifierType last_type = IDENTIFIER_MAX;
bool _find_identifier(const BlockNode *p_block, bool p_allow_reassign, const FunctionInfo &p_function_info, const StringName &p_identifier, DataType *r_data_type = nullptr, IdentifierType *r_type = nullptr, bool *r_is_const = nullptr, int *r_array_size = nullptr, StringName *r_struct_name = nullptr, ConstantNode::Value *r_constant_value = nullptr);
bool _find_identifier(const BlockNode *p_block, bool p_allow_reassign, const FunctionInfo &p_function_info, const StringName &p_identifier, DataType *r_data_type = nullptr, IdentifierType *r_type = nullptr, bool *r_is_const = nullptr, int *r_array_size = nullptr, StringName *r_struct_name = nullptr, Vector<Scalar> *r_constant_values = nullptr);
#ifdef DEBUG_ENABLED
void _parse_used_identifier(const StringName &p_identifier, IdentifierType p_type, const StringName &p_function);
#endif // DEBUG_ENABLED
bool _is_operator_assign(Operator p_op) const;
bool _validate_assign(Node *p_node, const FunctionInfo &p_function_info, String *r_message = nullptr);
bool _validate_operator(OperatorNode *p_op, DataType *r_ret_type = nullptr, int *r_ret_size = nullptr);
bool _validate_operator(const BlockNode *p_block, OperatorNode *p_op, DataType *r_ret_type = nullptr, int *r_ret_size = nullptr);
Vector<Scalar> _get_node_values(const BlockNode *p_block, Node *p_node);
bool _eval_operator(const BlockNode *p_block, OperatorNode *p_op);
Scalar _eval_unary_scalar(const Scalar &p_a, Operator p_op, DataType p_ret_type);
Scalar _eval_scalar(const Scalar &p_a, const Scalar &p_b, Operator p_op, DataType p_ret_type, bool &r_is_valid);
Vector<Scalar> _eval_unary_vector(const Vector<Scalar> &p_va, DataType p_ret_type, Operator p_op);
Vector<Scalar> _eval_vector(const Vector<Scalar> &p_va, const Vector<Scalar> &p_vb, DataType p_left_type, DataType p_right_type, DataType p_ret_type, Operator p_op, bool &r_is_valid);
Vector<Scalar> _eval_vector_transform(const Vector<Scalar> &p_va, const Vector<Scalar> &p_vb, DataType p_left_type, DataType p_right_type, DataType p_ret_type);
struct BuiltinEntry {
const char *name;