From d7d35e4f736b9a433e7a18000cc3c1028c9cb9f7 Mon Sep 17 00:00:00 2001 From: Hugo Locurcio Date: Thu, 18 Nov 2021 22:20:07 +0100 Subject: [PATCH] Add `const` qualifier support for function arguments in shaders This prevents the function argument from being reassigned within the function. Example: void test(const int t) {} --- drivers/gles2/shader_compiler_gles2.cpp | 15 +++++++++---- drivers/gles3/shader_compiler_gles3.cpp | 16 ++++++++++---- servers/visual/shader_language.cpp | 28 +++++++++++++++++++++++-- servers/visual/shader_language.h | 1 + 4 files changed, 50 insertions(+), 10 deletions(-) diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp index 78e21803835c..2727abdd9435 100644 --- a/drivers/gles2/shader_compiler_gles2.cpp +++ b/drivers/gles2/shader_compiler_gles2.cpp @@ -64,6 +64,13 @@ static String _prestr(SL::DataPrecision p_pres) { return ""; } +static String _constr(bool p_is_const) { + if (p_is_const) { + return "const "; + } + return ""; +} + static String _qualstr(SL::ArgumentQualifier p_qual) { switch (p_qual) { case SL::ARGUMENT_QUALIFIER_IN: @@ -254,6 +261,8 @@ void ShaderCompilerGLES2::_dump_function_deps(const SL::ShaderNode *p_node, cons header += ", "; } + header += _constr(fnode->arguments[i].is_const); + if (fnode->arguments[i].type == SL::TYPE_STRUCT) { header += _qualstr(fnode->arguments[i].qualifier) + _mkid(fnode->arguments[i].type_str) + " " + _mkid(fnode->arguments[i].name); } else { @@ -425,7 +434,7 @@ String ShaderCompilerGLES2::_dump_node_code(const SL::Node *p_node, int p_level, for (int i = 0; i < snode->vconstants.size(); i++) { String gcode; - gcode += "const "; + gcode += _constr(true); if (snode->vconstants[i].type == SL::TYPE_STRUCT) { gcode += _mkid(snode->vconstants[i].type_str); } else { @@ -517,9 +526,7 @@ String ShaderCompilerGLES2::_dump_node_code(const SL::Node *p_node, int p_level, SL::VariableDeclarationNode *var_dec_node = (SL::VariableDeclarationNode *)p_node; StringBuffer<> declaration; - if (var_dec_node->is_const) { - declaration += "const "; - } + declaration += _constr(var_dec_node->is_const); if (var_dec_node->datatype == SL::TYPE_STRUCT) { declaration += _mkid(var_dec_node->struct_name); } else { diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp index f81e2635a022..741d53781944 100644 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -213,6 +213,13 @@ static String _prestr(SL::DataPrecision p_pres) { return ""; } +static String _constr(bool p_is_const) { + if (p_is_const) { + return "const "; + } + return ""; +} + static String _qualstr(SL::ArgumentQualifier p_qual) { switch (p_qual) { case SL::ARGUMENT_QUALIFIER_IN: @@ -373,6 +380,9 @@ void ShaderCompilerGLES3::_dump_function_deps(const SL::ShaderNode *p_node, cons if (i > 0) { header += ", "; } + + header += _constr(fnode->arguments[i].is_const); + if (fnode->arguments[i].type == SL::TYPE_STRUCT) { header += _qualstr(fnode->arguments[i].qualifier) + _mkid(fnode->arguments[i].type_str) + " " + _mkid(fnode->arguments[i].name); } else { @@ -562,7 +572,7 @@ String ShaderCompilerGLES3::_dump_node_code(const SL::Node *p_node, int p_level, for (int i = 0; i < pnode->vconstants.size(); i++) { const SL::ShaderNode::Constant &cnode = pnode->vconstants[i]; String gcode; - gcode += "const "; + gcode += _constr(true); if (pnode->vconstants[i].type == SL::TYPE_STRUCT) { gcode += _mkid(cnode.type_str); } else { @@ -655,9 +665,7 @@ String ShaderCompilerGLES3::_dump_node_code(const SL::Node *p_node, int p_level, SL::VariableDeclarationNode *vdnode = (SL::VariableDeclarationNode *)p_node; String declaration; - if (vdnode->is_const) { - declaration += "const "; - } + declaration += _constr(vdnode->is_const); if (vdnode->datatype == SL::TYPE_STRUCT) { declaration += _mkid(vdnode->struct_name); } else { diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index 33ca355e64c5..559edc228295 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -953,6 +953,9 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, const Maparguments[i].type_str; } + if (r_is_const) { + *r_is_const = function->arguments[i].is_const; + } return true; } } @@ -3436,11 +3439,13 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons for (int i = 0; i < call_function->arguments.size(); i++) { int argidx = i + 1; if (argidx < func->arguments.size()) { - if (call_function->arguments[i].qualifier == ArgumentQualifier::ARGUMENT_QUALIFIER_OUT || call_function->arguments[i].qualifier == ArgumentQualifier::ARGUMENT_QUALIFIER_INOUT) { + if (call_function->arguments[i].is_const || call_function->arguments[i].qualifier == ArgumentQualifier::ARGUMENT_QUALIFIER_OUT || call_function->arguments[i].qualifier == ArgumentQualifier::ARGUMENT_QUALIFIER_INOUT) { bool error = false; Node *n = func->arguments[argidx]; if (n->type == Node::TYPE_CONSTANT || n->type == Node::TYPE_OPERATOR) { - error = true; + if (!call_function->arguments[i].is_const) { + error = true; + } } else if (n->type == Node::TYPE_ARRAY) { ArrayNode *an = static_cast(n); if (an->call_expression != nullptr || an->is_const) { @@ -6482,15 +6487,29 @@ Error ShaderLanguage::_parse_shader(const Map &p_funct break; } + bool is_const = false; + if (tk.type == TK_CONST) { + is_const = true; + tk = _get_token(); + } + ArgumentQualifier qualifier = ARGUMENT_QUALIFIER_IN; if (tk.type == TK_ARG_IN) { qualifier = ARGUMENT_QUALIFIER_IN; tk = _get_token(); } else if (tk.type == TK_ARG_OUT) { + if (is_const) { + _set_error("'out' qualifier cannot be used within a function parameter declared with 'const'."); + return ERR_PARSE_ERROR; + } qualifier = ARGUMENT_QUALIFIER_OUT; tk = _get_token(); } else if (tk.type == TK_ARG_INOUT) { + if (is_const) { + _set_error("'inout' qualifier cannot be used within a function parameter declared with 'const'."); + return ERR_PARSE_ERROR; + } qualifier = ARGUMENT_QUALIFIER_INOUT; tk = _get_token(); } @@ -6568,6 +6587,7 @@ Error ShaderLanguage::_parse_shader(const Map &p_funct arg.type_str = param_struct_name; arg.precision = pprecision; arg.qualifier = qualifier; + arg.is_const = is_const; func_node->arguments.push_back(arg); @@ -6977,6 +6997,10 @@ Error ShaderLanguage::complete(const String &p_code, const Mapfunctions[i].function->arguments[j].is_const) { + calltip += "const "; + } } if (shader->functions[i].function->arguments.size()) { diff --git a/servers/visual/shader_language.h b/servers/visual/shader_language.h index 30384efee298..80f9ec75a036 100644 --- a/servers/visual/shader_language.h +++ b/servers/visual/shader_language.h @@ -554,6 +554,7 @@ class ShaderLanguage { DataType type; StringName type_str; DataPrecision precision; + bool is_const; }; StringName name;