From af92fdb0ac1764bb58815d2fe7eb46bc4a1c50de Mon Sep 17 00:00:00 2001 From: Yuri Rubinsky Date: Mon, 1 Jul 2024 16:39:49 +0300 Subject: [PATCH] Add basic support to evaluate operator value in shader language --- drivers/gles3/storage/material_storage.cpp | 4 +- .../storage_rd/material_storage.cpp | 4 +- servers/rendering/shader_compiler.cpp | 2 +- servers/rendering/shader_language.cpp | 607 +++++++++++++++--- servers/rendering/shader_language.h | 44 +- 5 files changed, 540 insertions(+), 121 deletions(-) diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp index a37eba3b15a..7d5af48384c 100644 --- a/drivers/gles3/storage/material_storage.cpp +++ b/drivers/gles3/storage/material_storage.cpp @@ -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 &value, uint8_t *data) { +_FORCE_INLINE_ static void _fill_std140_ubo_value(ShaderLanguage::DataType type, const Vector &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 default_value = uniform.default_value; + Vector default_value = uniform.default_value; return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint); } return Variant(); diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp index 63dc54e24ca..9f390c99f91 100644 --- a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp @@ -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 &value, uint8_t *data) { +_FORCE_INLINE_ static void _fill_std140_ubo_value(ShaderLanguage::DataType type, const Vector &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 default_value = uniform.default_value; + Vector default_value = uniform.default_value; return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint); } return Variant(); diff --git a/servers/rendering/shader_compiler.cpp b/servers/rendering/shader_compiler.cpp index 49e005ca962..43703f86566 100644 --- a/servers/rendering/shader_compiler.cpp +++ b/servers/rendering/shader_compiler.cpp @@ -185,7 +185,7 @@ static String f2sp0(float p_float) { return num; } -static String get_constant_text(SL::DataType p_type, const Vector &p_values) { +static String get_constant_text(SL::DataType p_type, const Vector &p_values) { switch (p_type) { case SL::TYPE_BOOL: return p_values[0].boolean ? "true" : "false"; diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index 4eaf7fcb55b..2249cd2010f 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -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 *r_constant_values) { if (is_shader_inc) { for (int i = 0; i < RenderingServer::SHADER_MAX; i++) { for (const KeyValue &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(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::_get_node_values(const BlockNode *p_block, Node *p_node) { + Vector result; + + switch (p_node->type) { + case Node::NODE_TYPE_VARIABLE: { + _find_identifier(p_block, false, FunctionInfo(), static_cast(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 va = _get_node_values(p_block, p_op->arguments[0]); + Vector 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::_eval_unary_vector(const Vector &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(); // Non-evaluable values should not be parsed further. + } + Vector 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::_eval_vector(const Vector &p_va, const Vector &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(); // Non-evaluable values should not be parsed further. + } + + uint32_t ret_size = get_datatype_component_count(p_ret_type); + Vector 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::_eval_vector_transform(const Vector &p_va, const Vector &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(); // Non-evaluable values should not be parsed further. + } + + uint32_t ret_size = get_datatype_component_count(p_ret_type); + Vector 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(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) { + Vector 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 { - if (p_func->arguments[arg]->type == Node::NODE_TYPE_CONSTANT) { - const ConstantNode *cn = static_cast(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) { - error = true; - } - } else { - error = true; - } - } else { - error = true; - } + 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 &p_value, DataType p_type, int p_array_size, ShaderLanguage::ShaderNode::Uniform::Hint p_hint) { +Variant ShaderLanguage::constant_value_to_variant(const Vector &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 *r_keywords) { HashSet kws; @@ -4929,45 +5327,30 @@ Error ShaderLanguage::_parse_array_size(BlockNode *p_block, const FunctionInfo & *r_unknown_size = true; } } else { + _set_tkpos(pos); + int array_size = 0; + Node *expr = _parse_and_reduce_expression(p_block, p_function_info); - 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(n); - if (vn) { - ConstantNode::Value v; - DataType data_type; - bool is_const = false; + if (expr) { + Vector values = _get_node_values(p_block, expr); - _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::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; + 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 (((int)tk.constant) > 0) { - array_size = (uint32_t)tk.constant; + + if (r_size_expression != nullptr) { + *r_size_expression = expr; + } } if (array_size <= 0) { @@ -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::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::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::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::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::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(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 values; + Vector 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 values; + Vector 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(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 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 &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 { diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h index 63dca99654d..ba02e181b99 100644 --- a/servers/rendering/shader_language.h +++ b/servers/rendering/shader_language.h @@ -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 get_values() const { return Vector(); } Node(Type t) : type(t) {} @@ -402,11 +410,13 @@ public: Operator op = OP_EQUAL; StringName struct_name; Vector arguments; + Vector 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 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 values; + Vector values; Vector 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 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 values; }; HashMap variables; List 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 default_value; + Vector 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 &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 &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 *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 *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 _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 _eval_unary_vector(const Vector &p_va, DataType p_ret_type, Operator p_op); + Vector _eval_vector(const Vector &p_va, const Vector &p_vb, DataType p_left_type, DataType p_right_type, DataType p_ret_type, Operator p_op, bool &r_is_valid); + Vector _eval_vector_transform(const Vector &p_va, const Vector &p_vb, DataType p_left_type, DataType p_right_type, DataType p_ret_type); struct BuiltinEntry { const char *name;