summaryrefslogtreecommitdiffstats
path: root/servers/rendering/shader_language.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'servers/rendering/shader_language.cpp')
-rw-r--r--servers/rendering/shader_language.cpp473
1 files changed, 310 insertions, 163 deletions
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index 879a83f519..7c4128b0e3 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -356,7 +356,7 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = {
{ TK_CF_BREAK, "break", CF_BLOCK, {}, {} },
{ TK_CF_CONTINUE, "continue", CF_BLOCK, {}, {} },
{ TK_CF_RETURN, "return", CF_BLOCK, {}, {} },
- { TK_CF_DISCARD, "discard", CF_BLOCK, { "particles", "sky", "fog" }, { "fragment" } },
+ { TK_CF_DISCARD, "discard", CF_BLOCK, { "particles", "sky", "fog" }, { "vertex" } },
// function specifier keywords
@@ -1305,6 +1305,7 @@ void ShaderLanguage::clear() {
include_markers_handled.clear();
calls_info.clear();
+ function_overload_count.clear();
#ifdef DEBUG_ENABLED
keyword_completion_context = CF_UNSPECIFIED;
@@ -3554,6 +3555,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
ERR_FAIL_COND_V(p_func->arguments[0]->type != Node::NODE_TYPE_VARIABLE, false);
StringName name = static_cast<VariableNode *>(p_func->arguments[0])->name.operator String();
+ StringName rname = static_cast<VariableNode *>(p_func->arguments[0])->rname.operator String();
for (int i = 1; i < p_func->arguments.size(); i++) {
args.push_back(p_func->arguments[i]->get_datatype());
@@ -3563,28 +3565,33 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
int argcount = args.size();
- if (p_function_info.stage_functions.has(name)) {
- //stage based function
- const StageFunctionInfo &sf = p_function_info.stage_functions[name];
- if (argcount != sf.arguments.size()) {
- _set_error(vformat(RTR("Invalid number of arguments when calling stage function '%s', which expects %d arguments."), String(name), sf.arguments.size()));
- return false;
- }
- //validate arguments
- for (int i = 0; i < argcount; i++) {
- if (args[i] != sf.arguments[i].type) {
- _set_error(vformat(RTR("Invalid argument type when calling stage function '%s', type expected is '%s'."), String(name), get_datatype_name(sf.arguments[i].type)));
- return false;
- }
- }
+ if (stages) {
+ // Stage functions can be used in custom functions as well, that why need to check them all.
+ for (const KeyValue<StringName, FunctionInfo> &E : *stages) {
+ if (E.value.stage_functions.has(name)) {
+ // Stage-based function.
+ const StageFunctionInfo &sf = E.value.stage_functions[name];
+ if (argcount != sf.arguments.size()) {
+ _set_error(vformat(RTR("Invalid number of arguments when calling stage function '%s', which expects %d arguments."), String(name), sf.arguments.size()));
+ return false;
+ }
+ // Validate arguments.
+ for (int i = 0; i < argcount; i++) {
+ if (args[i] != sf.arguments[i].type) {
+ _set_error(vformat(RTR("Invalid argument type when calling stage function '%s', type expected is '%s'."), String(name), get_datatype_name(sf.arguments[i].type)));
+ return false;
+ }
+ }
- if (r_ret_type) {
- *r_ret_type = sf.return_type;
- }
- if (r_ret_type_str) {
- *r_ret_type_str = "";
+ if (r_ret_type) {
+ *r_ret_type = sf.return_type;
+ }
+ if (r_ret_type_str) {
+ *r_ret_type_str = "";
+ }
+ return true;
+ }
}
- return true;
}
bool failed_builtin = false;
@@ -3891,9 +3898,10 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
}
bool fail = false;
+ bool use_constant_conversion = function_overload_count[rname] == 0;
for (int j = 0; j < args.size(); j++) {
- if (get_scalar_type(args[j]) == args[j] && p_func->arguments[j + 1]->type == Node::NODE_TYPE_CONSTANT && args3[j] == 0 && convert_constant(static_cast<ConstantNode *>(p_func->arguments[j + 1]), pfunc->arguments[j].type)) {
+ if (use_constant_conversion && get_scalar_type(args[j]) == args[j] && p_func->arguments[j + 1]->type == Node::NODE_TYPE_CONSTANT && args3[j] == 0 && convert_constant(static_cast<ConstantNode *>(p_func->arguments[j + 1]), pfunc->arguments[j].type)) {
//all good, but it needs implicit conversion later
} else if (args[j] != pfunc->arguments[j].type || (args[j] == TYPE_STRUCT && args2[j] != pfunc->arguments[j].struct_name) || args3[j] != pfunc->arguments[j].array_size) {
String func_arg_name;
@@ -3919,7 +3927,7 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
arg_name += "]";
}
- _set_error(vformat(RTR("Invalid argument for \"%s(%s)\" function: argument %d should be %s but is %s."), String(name), arg_list, j + 1, func_arg_name, arg_name));
+ _set_error(vformat(RTR("Invalid argument for \"%s(%s)\" function: argument %d should be %s but is %s."), String(rname), arg_list, j + 1, func_arg_name, arg_name));
fail = true;
break;
}
@@ -3960,9 +3968,9 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
if (exists) {
if (last_arg_count > args.size()) {
- _set_error(vformat(RTR("Too few arguments for \"%s(%s)\" call. Expected at least %d but received %d."), String(name), arg_list, last_arg_count, args.size()));
+ _set_error(vformat(RTR("Too few arguments for \"%s(%s)\" call. Expected at least %d but received %d."), String(rname), arg_list, last_arg_count, args.size()));
} else if (last_arg_count < args.size()) {
- _set_error(vformat(RTR("Too many arguments for \"%s(%s)\" call. Expected at most %d but received %d."), String(name), arg_list, last_arg_count, args.size()));
+ _set_error(vformat(RTR("Too many arguments for \"%s(%s)\" call. Expected at most %d but received %d."), String(rname), arg_list, last_arg_count, args.size()));
}
}
@@ -5822,42 +5830,16 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
}
- const StringName &name = identifier;
-
- if (name != current_function) { // Recursion is not allowed.
- // Register call.
- if (calls_info.has(name)) {
- calls_info[current_function].calls.push_back(&calls_info[name]);
- }
-
- int idx = 0;
- bool is_builtin = false;
-
- while (frag_only_func_defs[idx].name) {
- if (frag_only_func_defs[idx].name == name) {
- // If a built-in function not found for the current shader type, then it shouldn't be parsed further.
- if (!is_supported_frag_only_funcs) {
- _set_error(vformat(RTR("Built-in function '%s' is not supported for the '%s' shader type."), name, shader_type_identifier));
- return nullptr;
- }
- // Register usage of the restricted function.
- calls_info[current_function].uses_restricted_items.push_back(Pair<StringName, CallInfo::Item>(name, CallInfo::Item(CallInfo::Item::ITEM_TYPE_BUILTIN, _get_tkpos())));
- is_builtin = true;
- break;
- }
- idx++;
- }
-
- // Recursively checks for the restricted function call.
- if (is_supported_frag_only_funcs && current_function == "vertex" && stages->has(current_function) && !_validate_restricted_func(name, &calls_info[current_function], is_builtin)) {
- return nullptr;
- }
- }
+ const StringName &rname = identifier;
+ StringName name = identifier;
OperatorNode *func = alloc_node<OperatorNode>();
func->op = OP_CALL;
+
VariableNode *funcname = alloc_node<VariableNode>();
funcname->name = name;
+ funcname->rname = name;
+
func->arguments.push_back(funcname);
int carg = -1;
@@ -5874,22 +5856,72 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
bnode = bnode->parent_block;
}
- //test if function was parsed first
+ // Test if function was parsed first.
int function_index = -1;
- for (int i = 0; i < shader->vfunctions.size(); i++) {
- if (shader->vfunctions[i].name == name) {
- //add to current function as dependency
- for (int j = 0; j < shader->vfunctions.size(); j++) {
- if (shader->vfunctions[j].name == current_function) {
- shader->vfunctions.write[j].uses_function.insert(name);
- break;
+ for (int i = 0, max_valid_args = 0; i < shader->vfunctions.size(); i++) {
+ if (!shader->vfunctions[i].callable || shader->vfunctions[i].rname != rname) {
+ continue;
+ }
+
+ bool found = true;
+ int valid_args = 0;
+
+ // Search for correct overload.
+ for (int j = 1; j < func->arguments.size(); j++) {
+ if (j - 1 == shader->vfunctions[i].function->arguments.size()) {
+ found = false;
+ break;
+ }
+
+ const FunctionNode::Argument &a = shader->vfunctions[i].function->arguments[j - 1];
+ Node *b = func->arguments[j];
+
+ if (a.type == b->get_datatype() && a.array_size == b->get_array_size()) {
+ if (a.type == TYPE_STRUCT) {
+ if (a.struct_name != b->get_datatype_name()) {
+ found = false;
+ break;
+ } else {
+ valid_args++;
+ }
+ } else {
+ valid_args++;
}
+ } else {
+ if (function_overload_count[rname] == 0 && get_scalar_type(a.type) == a.type && b->type == Node::NODE_TYPE_CONSTANT && a.array_size == 0 && convert_constant(static_cast<ConstantNode *>(b), a.type)) {
+ // Implicit cast if no overloads.
+ continue;
+ }
+ found = false;
+ break;
}
+ }
- //see if texture arguments must connect
- function_index = i;
- break;
+ // Using the best match index for completion hint if the function not found.
+ if (valid_args > max_valid_args) {
+ name = shader->vfunctions[i].name;
+ funcname->name = name;
+ max_valid_args = valid_args;
+ }
+
+ if (!found) {
+ continue;
}
+
+ // Add to current function as dependency.
+ for (int j = 0; j < shader->vfunctions.size(); j++) {
+ if (shader->vfunctions[j].name == current_function) {
+ shader->vfunctions.write[j].uses_function.insert(name);
+ break;
+ }
+ }
+
+ name = shader->vfunctions[i].name;
+ funcname->name = name;
+
+ // See if texture arguments must connect.
+ function_index = i;
+ break;
}
if (carg >= 0) {
@@ -5904,9 +5936,52 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
return nullptr;
}
+ if (name != current_function) { // Recursion is not allowed.
+ // Register call.
+ if (calls_info.has(name)) {
+ calls_info[current_function].calls.push_back(&calls_info[name]);
+ }
+
+ bool is_builtin = false;
+
+ if (is_supported_frag_only_funcs && stages) {
+ for (const KeyValue<StringName, FunctionInfo> &E : *stages) {
+ if (E.value.stage_functions.has(name)) {
+ // Register usage of the restricted stage function.
+ calls_info[current_function].uses_restricted_items.push_back(Pair<StringName, CallInfo::Item>(name, CallInfo::Item(CallInfo::Item::ITEM_TYPE_BUILTIN, _get_tkpos())));
+ is_builtin = true;
+ break;
+ }
+ }
+ }
+
+ if (!is_builtin) {
+ int idx = 0;
+ while (frag_only_func_defs[idx].name) {
+ if (frag_only_func_defs[idx].name == name) {
+ // If a built-in function not found for the current shader type, then it shouldn't be parsed further.
+ if (!is_supported_frag_only_funcs) {
+ _set_error(vformat(RTR("Built-in function '%s' is not supported for the '%s' shader type."), name, shader_type_identifier));
+ return nullptr;
+ }
+ // Register usage of the restricted function.
+ calls_info[current_function].uses_restricted_items.push_back(Pair<StringName, CallInfo::Item>(name, CallInfo::Item(CallInfo::Item::ITEM_TYPE_BUILTIN, _get_tkpos())));
+ is_builtin = true;
+ break;
+ }
+ idx++;
+ }
+ }
+
+ // Recursively checks for the restricted function call.
+ if (is_supported_frag_only_funcs && current_function == "vertex" && stages->has(current_function) && !_validate_restricted_func(name, &calls_info[current_function], is_builtin)) {
+ return nullptr;
+ }
+ }
+
bool is_custom_func = false;
if (!_validate_function_call(p_block, p_function_info, func, &func->return_cache, &func->struct_name, &is_custom_func)) {
- _set_error(vformat(RTR("No matching function found for: '%s'."), String(funcname->name)));
+ _set_error(vformat(RTR("No matching function found for: '%s'."), String(funcname->rname)));
return nullptr;
}
completion_class = TAG_GLOBAL; // reset sub-class
@@ -6095,7 +6170,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
expr = func;
#ifdef DEBUG_ENABLED
- if (check_warnings) {
+ if (check_warnings && is_custom_func) {
StringName func_name;
if (p_block && p_block->parent_function) {
@@ -8524,6 +8599,11 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
block = block->parent_block;
}
} else if (tk.type == TK_CF_DISCARD) {
+ if (!is_discard_supported) {
+ _set_error(vformat(RTR("Use of '%s' is not supported for the '%s' shader type."), "discard", shader_type_identifier));
+ return ERR_PARSE_ERROR;
+ }
+
//check return type
BlockNode *b = p_block;
while (b && !b->parent_function) {
@@ -8535,7 +8615,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
}
if (!b->parent_function->can_discard) {
- _set_error(vformat(RTR("Use of '%s' is not allowed here."), "discard"));
+ _set_error(vformat(RTR("'%s' cannot be used within the '%s' processor function."), "discard", b->parent_function->name));
return ERR_PARSE_ERROR;
}
@@ -8544,6 +8624,9 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
pos = _get_tkpos();
tk = _get_token();
+
+ calls_info[b->parent_function->name].uses_restricted_items.push_back(Pair<StringName, CallInfo::Item>("discard", CallInfo::Item(CallInfo::Item::ITEM_TYPE_BUILTIN, pos)));
+
if (tk.type != TK_SEMICOLON) {
_set_expected_after_error(";", "discard");
return ERR_PARSE_ERROR;
@@ -8781,7 +8864,9 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
ShaderNode::Uniform::Scope uniform_scope = ShaderNode::Uniform::SCOPE_LOCAL;
stages = &p_functions;
- is_supported_frag_only_funcs = shader_type_identifier == "canvas_item" || shader_type_identifier == "spatial" || shader_type_identifier == "sky";
+
+ is_discard_supported = shader_type_identifier == "canvas_item" || shader_type_identifier == "spatial";
+ is_supported_frag_only_funcs = is_discard_supported || shader_type_identifier == "sky";
const FunctionInfo &constants = p_functions.has("constants") ? p_functions["constants"] : FunctionInfo();
@@ -9089,10 +9174,6 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
_set_error(vformat(RTR("Uniform instances are not yet implemented for '%s' shaders."), shader_type_identifier));
return ERR_PARSE_ERROR;
}
- if (OS::get_singleton()->get_current_rendering_method() == "gl_compatibility") {
- _set_error(RTR("Uniform instances are not supported in gl_compatibility shaders."));
- return ERR_PARSE_ERROR;
- }
if (uniform_scope == ShaderNode::Uniform::SCOPE_LOCAL) {
tk = _get_token();
if (tk.type != TK_UNIFORM) {
@@ -9936,7 +10017,8 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
return ERR_PARSE_ERROR;
}
- if (shader->structs.has(name) || _find_identifier(nullptr, false, constants, name) || has_builtin(p_functions, name, !is_constant)) {
+ IdentifierType itype;
+ if (shader->structs.has(name) || (_find_identifier(nullptr, false, constants, name, nullptr, &itype) && itype != IDENTIFIER_FUNCTION) || has_builtin(p_functions, name, !is_constant)) {
_set_redefinition_error(String(name));
return ERR_PARSE_ERROR;
}
@@ -10264,20 +10346,13 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
function.callable = !p_functions.has(name);
function.name = name;
+ function.rname = name;
FunctionNode *func_node = alloc_node<FunctionNode>();
-
function.function = func_node;
- shader->functions.insert(name, function);
- shader->vfunctions.push_back(function);
-
- CallInfo call_info;
- call_info.name = name;
-
- calls_info.insert(name, call_info);
-
func_node->name = name;
+ func_node->rname = name;
func_node->return_type = type;
func_node->return_struct_name = struct_name;
func_node->return_precision = precision;
@@ -10286,11 +10361,13 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
if (p_functions.has(name)) {
func_node->can_discard = p_functions[name].can_discard;
} else {
-#ifdef DEBUG_ENABLED
- if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_FUNCTION_FLAG)) {
- used_functions.insert(name, Usage(tk_line));
- }
-#endif // DEBUG_ENABLED
+ func_node->can_discard = is_discard_supported; // Allow use it for custom functions (in supported shader types).
+ }
+
+ if (!function_overload_count.has(name)) {
+ function_overload_count.insert(name, 0);
+ } else {
+ function_overload_count[name]++;
}
func_node->body = alloc_node<BlockNode>();
@@ -10470,7 +10547,6 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
param_name = tk.text;
- ShaderLanguage::IdentifierType itype;
if (_find_identifier(func_node->body, false, builtins, param_name, (ShaderLanguage::DataType *)nullptr, &itype)) {
if (itype != IDENTIFIER_FUNCTION) {
_set_redefinition_error(String(param_name));
@@ -10516,6 +10592,66 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
}
}
+ // Searches for function index and check for the exact duplicate in overloads.
+ int function_index = 0;
+ for (int i = 0; i < shader->vfunctions.size(); i++) {
+ if (!shader->vfunctions[i].callable || shader->vfunctions[i].rname != name) {
+ continue;
+ }
+
+ function_index++;
+
+ if (shader->vfunctions[i].function->arguments.size() != func_node->arguments.size()) {
+ continue;
+ }
+
+ bool is_same = true;
+
+ for (int j = 0; j < shader->vfunctions[i].function->arguments.size(); j++) {
+ FunctionNode::Argument a = func_node->arguments[j];
+ FunctionNode::Argument b = shader->vfunctions[i].function->arguments[j];
+
+ if (a.type == b.type && a.array_size == b.array_size) {
+ if (a.type == TYPE_STRUCT) {
+ is_same = a.struct_name == b.struct_name;
+ }
+ } else {
+ is_same = false;
+ }
+
+ if (!is_same) {
+ break;
+ }
+ }
+
+ if (is_same) {
+ _set_redefinition_error(String(name));
+ return ERR_PARSE_ERROR;
+ }
+ }
+
+ // Creates a fake name for function overload, which will be replaced by the real name by the compiler.
+ String name2 = name;
+ if (function_index > 0) {
+ name2 = vformat("%s@%s", name, itos(function_index + 1));
+
+ function.name = name2;
+ func_node->name = name2;
+ }
+
+ shader->functions.insert(name2, function);
+ shader->vfunctions.push_back(function);
+
+ CallInfo call_info;
+ call_info.name = name2;
+ calls_info.insert(name2, call_info);
+
+#ifdef DEBUG_ENABLED
+ if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_FUNCTION_FLAG) && !p_functions.has(name)) {
+ used_functions.insert(name2, Usage(tk_line));
+ }
+#endif // DEBUG_ENABLED
+
if (p_functions.has(name)) {
//if one of the core functions, make sure they are of the correct form
if (func_node->arguments.size() > 0) {
@@ -10535,7 +10671,7 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
return ERR_PARSE_ERROR;
}
- current_function = name;
+ current_function = name2;
#ifdef DEBUG_ENABLED
keyword_completion_context = CF_BLOCK;
@@ -10816,10 +10952,7 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
break; // Ignore hint keywords (parsed below).
}
if (keyword_list[i].flags & keyword_completion_context) {
- if (keyword_list[i].excluded_shader_types.has(shader_type_identifier)) {
- continue;
- }
- if (!keyword_list[i].functions.is_empty() && !keyword_list[i].functions.has(current_function)) {
+ if (keyword_list[i].excluded_shader_types.has(shader_type_identifier) || keyword_list[i].excluded_functions.has(current_function)) {
continue;
}
ScriptLanguage::CodeCompletionOption option(keyword_list[i].text, ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
@@ -11048,15 +11181,21 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
if (!shader->vfunctions[i].callable || shader->vfunctions[i].name == skip_function) {
continue;
}
- matches.insert(String(shader->vfunctions[i].name), ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
+ matches.insert(String(shader->vfunctions[i].rname), ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
}
int idx = 0;
bool low_end = RenderingServer::get_singleton()->is_low_end();
- if (stages && stages->has(skip_function)) {
- for (const KeyValue<StringName, StageFunctionInfo> &E : (*stages)[skip_function].stage_functions) {
- matches.insert(String(E.key), ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
+ if (stages) {
+ // Stage functions can be used in custom functions as well, that why need to check them all.
+ for (const KeyValue<StringName, FunctionInfo> &E : *stages) {
+ for (const KeyValue<StringName, StageFunctionInfo> &F : E.value.stage_functions) {
+ if (F.value.skip_function == skip_function && stages->has(skip_function)) {
+ continue;
+ }
+ matches.insert(String(F.key), ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
+ }
}
}
@@ -11099,6 +11238,7 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
case COMPLETION_CALL_ARGUMENTS: {
StringName block_function;
BlockNode *block = completion_block;
+ String calltip;
while (block) {
if (block->parent_function) {
@@ -11107,89 +11247,93 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
block = block->parent_block;
}
- for (int i = 0; i < shader->vfunctions.size(); i++) {
- if (!shader->vfunctions[i].callable) {
+ for (int i = 0, overload_index = 0; i < shader->vfunctions.size(); i++) {
+ if (!shader->vfunctions[i].callable || shader->vfunctions[i].rname != completion_function) {
continue;
}
- if (shader->vfunctions[i].name == completion_function) {
- String calltip;
-
- if (shader->vfunctions[i].function->return_type == TYPE_STRUCT) {
- calltip += String(shader->vfunctions[i].function->return_struct_name);
- } else {
- calltip += get_datatype_name(shader->vfunctions[i].function->return_type);
- }
- if (shader->vfunctions[i].function->return_array_size > 0) {
- calltip += "[";
- calltip += itos(shader->vfunctions[i].function->return_array_size);
- calltip += "]";
- }
+ if (shader->vfunctions[i].function->return_type == TYPE_STRUCT) {
+ calltip += String(shader->vfunctions[i].function->return_struct_name);
+ } else {
+ calltip += get_datatype_name(shader->vfunctions[i].function->return_type);
+ }
- calltip += " ";
- calltip += shader->vfunctions[i].name;
- calltip += "(";
+ if (shader->vfunctions[i].function->return_array_size > 0) {
+ calltip += "[";
+ calltip += itos(shader->vfunctions[i].function->return_array_size);
+ calltip += "]";
+ }
- for (int j = 0; j < shader->vfunctions[i].function->arguments.size(); j++) {
- if (j > 0) {
- calltip += ", ";
- } else {
- calltip += " ";
- }
+ calltip += " ";
+ calltip += shader->vfunctions[i].rname;
+ calltip += "(";
- if (j == completion_argument) {
- calltip += char32_t(0xFFFF);
- }
+ for (int j = 0; j < shader->vfunctions[i].function->arguments.size(); j++) {
+ if (j > 0) {
+ calltip += ", ";
+ } else {
+ calltip += " ";
+ }
- if (shader->vfunctions[i].function->arguments[j].is_const) {
- calltip += "const ";
- }
+ if (j == completion_argument) {
+ calltip += char32_t(0xFFFF);
+ }
- if (shader->vfunctions[i].function->arguments[j].qualifier != ArgumentQualifier::ARGUMENT_QUALIFIER_IN) {
- if (shader->vfunctions[i].function->arguments[j].qualifier == ArgumentQualifier::ARGUMENT_QUALIFIER_OUT) {
- calltip += "out ";
- } else { // ArgumentQualifier::ARGUMENT_QUALIFIER_INOUT
- calltip += "inout ";
- }
- }
+ if (shader->vfunctions[i].function->arguments[j].is_const) {
+ calltip += "const ";
+ }
- if (shader->vfunctions[i].function->arguments[j].type == TYPE_STRUCT) {
- calltip += String(shader->vfunctions[i].function->arguments[j].struct_name);
- } else {
- calltip += get_datatype_name(shader->vfunctions[i].function->arguments[j].type);
+ if (shader->vfunctions[i].function->arguments[j].qualifier != ArgumentQualifier::ARGUMENT_QUALIFIER_IN) {
+ if (shader->vfunctions[i].function->arguments[j].qualifier == ArgumentQualifier::ARGUMENT_QUALIFIER_OUT) {
+ calltip += "out ";
+ } else { // ArgumentQualifier::ARGUMENT_QUALIFIER_INOUT
+ calltip += "inout ";
}
- calltip += " ";
- calltip += shader->vfunctions[i].function->arguments[j].name;
+ }
- if (shader->vfunctions[i].function->arguments[j].array_size > 0) {
- calltip += "[";
- calltip += itos(shader->vfunctions[i].function->arguments[j].array_size);
- calltip += "]";
- }
+ if (shader->vfunctions[i].function->arguments[j].type == TYPE_STRUCT) {
+ calltip += String(shader->vfunctions[i].function->arguments[j].struct_name);
+ } else {
+ calltip += get_datatype_name(shader->vfunctions[i].function->arguments[j].type);
+ }
+ calltip += " ";
+ calltip += shader->vfunctions[i].function->arguments[j].name;
- if (j == completion_argument) {
- calltip += char32_t(0xFFFF);
- }
+ if (shader->vfunctions[i].function->arguments[j].array_size > 0) {
+ calltip += "[";
+ calltip += itos(shader->vfunctions[i].function->arguments[j].array_size);
+ calltip += "]";
}
- if (shader->vfunctions[i].function->arguments.size()) {
- calltip += " ";
+ if (j == completion_argument) {
+ calltip += char32_t(0xFFFF);
}
- calltip += ")";
+ }
- r_call_hint = calltip;
- return OK;
+ if (shader->vfunctions[i].function->arguments.size()) {
+ calltip += " ";
}
- }
+ calltip += ")";
- int idx = 0;
+ if (overload_index < function_overload_count[shader->vfunctions[i].rname]) {
+ overload_index++;
+ calltip += "\n";
+ continue;
+ }
- String calltip;
- bool low_end = RenderingServer::get_singleton()->is_low_end();
+ r_call_hint = calltip;
+ return OK;
+ }
+
+ if (stages) {
+ // Stage functions can be used in custom functions as well, that why need to check them all.
+ for (const KeyValue<StringName, FunctionInfo> &S : *stages) {
+ for (const KeyValue<StringName, StageFunctionInfo> &E : S.value.stage_functions) {
+ // No need to check for the skip function here.
+ if (completion_function != E.key) {
+ continue;
+ }
- if (stages && stages->has(block_function)) {
- for (const KeyValue<StringName, StageFunctionInfo> &E : (*stages)[block_function].stage_functions) {
- if (completion_function == E.key) {
calltip += get_datatype_name(E.value.return_type);
calltip += " ";
calltip += E.key;
@@ -11226,6 +11370,9 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
}
}
+ int idx = 0;
+ bool low_end = RenderingServer::get_singleton()->is_low_end();
+
while (builtin_func_defs[idx].name) {
if ((low_end && builtin_func_defs[idx].high_end) || _check_restricted_func(builtin_func_defs[idx].name, block_function)) {
idx++;