Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow using stage functions inside custom shader functions #93650

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 68 additions & 38 deletions servers/rendering/shader_language.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3124,28 +3124,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;
Expand Down Expand Up @@ -5342,22 +5347,35 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
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;
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_functions.push_back(Pair<StringName, TkPos>(name, _get_tkpos()));
is_builtin = true;
break;
}
// Register usage of the restricted function.
calls_info[current_function].uses_restricted_functions.push_back(Pair<StringName, TkPos>(name, _get_tkpos()));
is_builtin = true;
break;
}
idx++;
}

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 built-in function.
calls_info[current_function].uses_restricted_functions.push_back(Pair<StringName, TkPos>(name, _get_tkpos()));
is_builtin = true;
break;
}
idx++;
}
}

// Recursively checks for the restricted function call.
Expand Down Expand Up @@ -10425,9 +10443,15 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
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);
}
}
}

Expand Down Expand Up @@ -10558,9 +10582,15 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
String calltip;
bool low_end = RenderingServer::get_singleton()->is_low_end();

if (stages && stages->has(block_function)) {
for (const KeyValue<StringName, StageFunctionInfo> &E : (*stages)[block_function].stage_functions) {
if (completion_function == E.key) {
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;
}

calltip += get_datatype_name(E.value.return_type);
calltip += " ";
calltip += E.key;
Expand Down
1 change: 1 addition & 0 deletions servers/rendering/shader_language.h
Original file line number Diff line number Diff line change
Expand Up @@ -824,6 +824,7 @@ class ShaderLanguage {

Vector<Argument> arguments;
DataType return_type = TYPE_VOID;
String skip_function;
};

struct ModeInfo {
Expand Down
2 changes: 2 additions & 0 deletions servers/rendering/shader_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ ShaderTypes::ShaderTypes() {

{
ShaderLanguage::StageFunctionInfo func;
func.skip_function = "vertex";
func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("sdf_pos", ShaderLanguage::TYPE_VEC2));
func.return_type = ShaderLanguage::TYPE_FLOAT; //whether it could emit
shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].stage_functions["texture_sdf"] = func;
Expand All @@ -294,6 +295,7 @@ ShaderTypes::ShaderTypes() {

{
ShaderLanguage::StageFunctionInfo func;
func.skip_function = "vertex";
func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("uv", ShaderLanguage::TYPE_VEC2));
func.return_type = ShaderLanguage::TYPE_VEC2; //whether it could emit
shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].stage_functions["screen_uv_to_sdf"] = func;
Expand Down
Loading