From 257e84a5fc8638d84b60b576af734c17baac266c Mon Sep 17 00:00:00 2001 From: Radiant <69520693+RadiantUwU@users.noreply.github.com> Date: Thu, 5 Dec 2024 22:58:37 +0200 Subject: [PATCH] Implement multi-pass shader directive.l --- editor/plugins/text_shader_editor.cpp | 4 +-- .../plugins/visual_shader_editor_plugin.cpp | 2 +- scene/resources/shader.cpp | 2 +- scene/resources/shader_include.cpp | 2 +- servers/rendering/shader_preprocessor.cpp | 25 ++++++++++++++++++- servers/rendering/shader_preprocessor.h | 4 ++- 6 files changed, 32 insertions(+), 7 deletions(-) diff --git a/editor/plugins/text_shader_editor.cpp b/editor/plugins/text_shader_editor.cpp index 0ff7aaa3fe46..54b8521bd3d9 100644 --- a/editor/plugins/text_shader_editor.cpp +++ b/editor/plugins/text_shader_editor.cpp @@ -409,7 +409,7 @@ void ShaderTextEditor::_code_complete_script(const String &p_code, Listget_path(); } - last_compile_result = preprocessor.preprocess(code, filename, code_pp, &error_pp, &err_positions, ®ions); + last_compile_result = preprocessor.preprocess(code, filename, code_pp, nullptr, &error_pp, &err_positions, ®ions); for (int i = 0; i < get_text_editor()->get_line_count(); i++) { get_text_editor()->set_line_background_color(i, Color(0, 0, 0, 0)); diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 31e158bba73e..2016386c0cd7 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -6241,7 +6241,7 @@ void VisualShaderEditor::_update_preview() { String error_pp; List err_positions; ShaderPreprocessor preprocessor; - Error err = preprocessor.preprocess(code, path, preprocessed_code, &error_pp, &err_positions); + Error err = preprocessor.preprocess(code, path, preprocessed_code, nullptr, &error_pp, &err_positions); if (err != OK) { ERR_FAIL_COND(err_positions.is_empty()); diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp index d163a42fa9f1..9cc935497414 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -100,7 +100,7 @@ void Shader::set_code(const String &p_code) { // 2) Server does not do interaction with Resource filetypes, this is a scene level feature. HashSet> new_include_dependencies; ShaderPreprocessor preprocessor; - Error result = preprocessor.preprocess(p_code, path, preprocessed_code, nullptr, nullptr, nullptr, &new_include_dependencies); + Error result = preprocessor.preprocess(p_code, path, preprocessed_code, nullptr, nullptr, nullptr, nullptr, &new_include_dependencies); if (result == OK) { // This ensures previous include resources are not freed and then re-loaded during parse (which would make compiling slower) include_dependencies = new_include_dependencies; diff --git a/scene/resources/shader_include.cpp b/scene/resources/shader_include.cpp index 0a2a686b4e17..8d9a8d1c0a61 100644 --- a/scene/resources/shader_include.cpp +++ b/scene/resources/shader_include.cpp @@ -52,7 +52,7 @@ void ShaderInclude::set_code(const String &p_code) { String pp_code; HashSet> new_dependencies; ShaderPreprocessor preprocessor; - Error result = preprocessor.preprocess(p_code, path, pp_code, nullptr, nullptr, nullptr, &new_dependencies); + Error result = preprocessor.preprocess(p_code, path, pp_code, nullptr, nullptr, nullptr, nullptr, &new_dependencies); if (result == OK) { // This ensures previous include resources are not freed and then re-loaded during parse (which would make compiling slower) dependencies = new_dependencies; diff --git a/servers/rendering/shader_preprocessor.cpp b/servers/rendering/shader_preprocessor.cpp index 88ea74cdfcd5..62682a46bb74 100644 --- a/servers/rendering/shader_preprocessor.cpp +++ b/servers/rendering/shader_preprocessor.cpp @@ -826,6 +826,20 @@ void ShaderPreprocessor::process_undef(Tokenizer *p_tokenizer) { } } +void ShaderPreprocessor::process_pass(Tokenizer *p_tokenizer) { + const int line = p_tokenizer->get_line(); + const String label = p_tokenizer->get_identifier(); + if (label.is_empty() || !p_tokenizer->consume_empty_line()) { + set_error(vformat(RTR("Invalid '%s' directive."), "pass"), line); + return; + } + + if (state->defines.has(label)) { + set_error(vformat(RTR("Cannot use pass directive '%s' if it's been already defined previously."), label), line); + return; + } +} + void ShaderPreprocessor::add_region(int p_line, bool p_enabled, Region *p_parent_region) { Region region; region.file = state->current_filename; @@ -1323,7 +1337,7 @@ Error ShaderPreprocessor::preprocess(State *p_state, const String &p_code, Strin return OK; } -Error ShaderPreprocessor::preprocess(const String &p_code, const String &p_filename, String &r_result, String *r_error_text, List *r_error_position, List *r_regions, HashSet> *r_includes, List *r_completion_options, List *r_completion_defines, IncludeCompletionFunction p_include_completion_func) { +Error ShaderPreprocessor::preprocess(const String &p_code, const String &p_filename, String &r_result, String *p_pass, String *r_error_text, List *r_error_position, List *r_regions, HashSet> *r_includes, List *r_completion_options, List *r_completion_defines, IncludeCompletionFunction p_include_completion_func, Vector *r_passes) { State pp_state; if (!p_filename.is_empty()) { pp_state.current_filename = p_filename; @@ -1356,6 +1370,12 @@ Error ShaderPreprocessor::preprocess(const String &p_code, const String &p_filen define->body = E.value; pp_state.defines[E.key] = define; } + + if (p_pass) { + Define *define = memnew(Define); + define->is_builtin = true; + pp_state.defines[*p_pass] = define; + } } Error err = preprocess(&pp_state, p_code, r_result); @@ -1367,6 +1387,9 @@ Error ShaderPreprocessor::preprocess(const String &p_code, const String &p_filen *r_error_position = pp_state.include_positions; } } + if (r_passes) { + *r_passes = pp_state.passes; + } if (r_regions) { *r_regions = pp_state.regions[p_filename]; } diff --git a/servers/rendering/shader_preprocessor.h b/servers/rendering/shader_preprocessor.h index b3d9594bcbb6..c73fdce6b432 100644 --- a/servers/rendering/shader_preprocessor.h +++ b/servers/rendering/shader_preprocessor.h @@ -166,6 +166,7 @@ class ShaderPreprocessor { bool disabled = false; CompletionType completion_type = COMPLETION_TYPE_NONE; HashSet> shader_includes; + Vector passes; }; private: @@ -199,6 +200,7 @@ class ShaderPreprocessor { void process_include(Tokenizer *p_tokenizer); void process_pragma(Tokenizer *p_tokenizer); void process_undef(Tokenizer *p_tokenizer); + void process_pass(Tokenizer *p_tokenizer); void add_region(int p_line, bool p_enabled, Region *p_parent_region); void start_branch_condition(Tokenizer *p_tokenizer, bool p_success, bool p_continue = false); @@ -223,7 +225,7 @@ class ShaderPreprocessor { public: typedef void (*IncludeCompletionFunction)(List *); - Error preprocess(const String &p_code, const String &p_filename, String &r_result, String *r_error_text = nullptr, List *r_error_position = nullptr, List *r_regions = nullptr, HashSet> *r_includes = nullptr, List *r_completion_options = nullptr, List *r_completion_defines = nullptr, IncludeCompletionFunction p_include_completion_func = nullptr); + Error preprocess(const String &p_code, const String &p_filename, String &r_result, String *p_pass = nullptr, String *r_error_text = nullptr, List *r_error_position = nullptr, List *r_regions = nullptr, HashSet> *r_includes = nullptr, List *r_completion_options = nullptr, List *r_completion_defines = nullptr, IncludeCompletionFunction p_include_completion_func = nullptr, Vector *r_passes = nullptr); static void get_keyword_list(List *r_keywords, bool p_include_shader_keywords, bool p_ignore_context_keywords = false); static void get_pragma_list(List *r_pragmas);