diff --git a/doc/classes/BaseMaterial3D.xml b/doc/classes/BaseMaterial3D.xml index fc8af02869eb..8e2cffbe26f2 100644 --- a/doc/classes/BaseMaterial3D.xml +++ b/doc/classes/BaseMaterial3D.xml @@ -348,6 +348,10 @@ Specifies the channel of the [member roughness_texture] in which the roughness information is stored. This is useful when you store the information for multiple effects in a single texture. For example if you stored metallic in the red channel, roughness in the blue, and ambient occlusion in the green you could reduce the number of textures you use. + + Optionally set a custom shader template. If empty the built-in shader template will be used. + [b]Node:[/b] Material features may not be supported by the selected shader template. + Sets whether the shading takes place, per-pixel, per-vertex or unshaded. Per-vertex lighting is faster, making it the best choice for mobile applications, however it looks considerably worse than per-pixel. Unshaded rendering is the fastest, but disables all interactions with lights. [b]Note:[/b] Setting the shading mode vertex shading currently has no effect, as vertex shading is not implemented yet. diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index cea9a4cec43b..fb171fbacd0d 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -3330,6 +3330,7 @@ Sets the shader's source code (which triggers recompilation after being changed). + [b]Note:[/b] if your shader uses a custom shader template, make sure to call [method shader_set_shader_template] first to prevent two (re)compilations! @@ -3351,6 +3352,34 @@ Sets the path hint for the specified shader. This should generally match the [Shader] resource's [member Resource.resource_path]. + + + + + + + Set the shader template to use with this shader. If not set the built-in template is used. + [b]Note:[/b] if [method shader_set_code] was previously called, this will trigger a recompile with the new template. If you are about to update the code as well you can set [param clear_code] to [code]true[/code] to prevent an unnecessary compile step. + + + + + + Creates an empty shader template and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID will be used in all [code]shader_template_*[/code] RenderingServer functions. + Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] method. + [b]Note:[/b] The equivalent resource is ShaderTemplate. + + + + + + + + + + Set the vertex and fragment code for the shader template. [param name] is used for caching this shader. + + diff --git a/doc/classes/ShaderTemplate.xml b/doc/classes/ShaderTemplate.xml new file mode 100644 index 000000000000..8279ba76089f --- /dev/null +++ b/doc/classes/ShaderTemplate.xml @@ -0,0 +1,25 @@ + + + + A shader template contains the template GLSL code into which user shader code is injected. + + + Shader templates form the heart of Godots shader code. Godot has a built-in template for each renderer and shader mode into which user shader code is injected. Shader Templates allow you to create custom versions of these shaders and gain fine grained control over the shaders. + [b]Warning[/b], this is a highly advanced feature that requires intimate knowledge of Godots renderers. It is highly likely that as Godots internal shaders evolve with each new release of Godot, that this will impact any custom shader templates you create. The aim is to improve this over time however full backwards compatibility is not something we can guarantee in this feature. + + + + + + + + Get shader mode for this shader template. + + + + + + The shader code for this shader template. + + + diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp index a37eba3b15ac..3e265fcf2370 100644 --- a/drivers/gles3/storage/material_storage.cpp +++ b/drivers/gles3/storage/material_storage.cpp @@ -2126,6 +2126,37 @@ void MaterialStorage::_update_global_shader_uniforms() { } } +/* SHADER TEMPLATE API */ + +void GLES3::ShaderTemplate::cleanup() { + if (shader) { + memdelete(shader); + shader = nullptr; + } +} + +RID MaterialStorage::shader_template_allocate() { + return shader_template_owner.allocate_rid(); +} + +void MaterialStorage::shader_template_initialize(RID p_rid) { + ShaderTemplate shader_template; + shader_template.shader = nullptr; + shader_template_owner.initialize_rid(p_rid, shader_template); +} + +void MaterialStorage::shader_template_free(RID p_rid) { + ShaderTemplate *shader_template = shader_template_owner.get_or_null(p_rid); + ERR_FAIL_NULL(shader_template); + + shader_template->cleanup(); + shader_template_owner.free(p_rid); +} + +void MaterialStorage::shader_template_set_raster_code(RID p_template_shader, const String &p_vertex_code, const String &p_fragment_code, const String &p_name) { + // Not supported in compatibility (yet). +} + /* SHADER API */ RID MaterialStorage::shader_allocate() { @@ -2156,6 +2187,15 @@ void MaterialStorage::shader_free(RID p_rid) { shader_owner.free(p_rid); } +void MaterialStorage::shader_set_shader_template(RID p_shader, RID p_shader_template, bool p_clear_code) { + GLES3::Shader *shader = shader_owner.get_or_null(p_shader); + ERR_FAIL_NULL(shader); + + if (shader->shader_template != p_shader_template) { + shader->shader_template = p_shader_template; + } +} + void MaterialStorage::shader_set_code(RID p_shader, const String &p_code) { GLES3::Shader *shader = shader_owner.get_or_null(p_shader); ERR_FAIL_NULL(shader); @@ -2224,7 +2264,7 @@ void MaterialStorage::shader_set_code(RID p_shader, const String &p_code) { } if (shader->data) { - shader->data->set_code(p_code); + shader->data->set_code(p_code, shader->shader_template); } for (Material *E : shader->owners) { @@ -2530,7 +2570,12 @@ LocalVector get_texture_uniform_data(const Vect /* Canvas Shader Data */ -void CanvasShaderData::set_code(const String &p_code) { +void CanvasShaderData::set_code(const String &p_code, RID p_shader_template) { + // Shader template isn't supported here yet. + if (p_shader_template.is_valid()) { + WARN_PRINT_ONCE("Shader templates are not supported for canvas shaders."); + } + // Initialize and compile the shader. code = p_code; @@ -2697,7 +2742,12 @@ GLES3::MaterialData *GLES3::_create_canvas_material_func(ShaderData *p_shader) { //////////////////////////////////////////////////////////////////////////////// // SKY SHADER -void SkyShaderData::set_code(const String &p_code) { +void SkyShaderData::set_code(const String &p_code, RID p_shader_template) { + // Shader template isn't supported here yet. + if (p_shader_template.is_valid()) { + WARN_PRINT_ONCE("Shader templates are not supported for sky shaders."); + } + // Initialize and compile the shader. code = p_code; @@ -2839,7 +2889,12 @@ void SkyMaterialData::bind_uniforms() { //////////////////////////////////////////////////////////////////////////////// // Scene SHADER -void SceneShaderData::set_code(const String &p_code) { +void SceneShaderData::set_code(const String &p_code, RID p_shader_template) { + // Shader template isn't supported here yet. + if (p_shader_template.is_valid()) { + WARN_PRINT_ONCE("Shader templates are not supported on the compatibility render."); + } + // Initialize and compile the shader. code = p_code; @@ -3117,7 +3172,12 @@ void SceneMaterialData::bind_uniforms() { /* Particles SHADER */ -void ParticlesShaderData::set_code(const String &p_code) { +void ParticlesShaderData::set_code(const String &p_code, RID p_shader_template) { + // Shader template isn't supported here yet. + if (p_shader_template.is_valid()) { + WARN_PRINT_ONCE("Shader templates are not supported for particle shaders."); + } + // Initialize and compile the shader. code = p_code; diff --git a/drivers/gles3/storage/material_storage.h b/drivers/gles3/storage/material_storage.h index 392ebcc570d9..936b86f9baf9 100644 --- a/drivers/gles3/storage/material_storage.h +++ b/drivers/gles3/storage/material_storage.h @@ -63,7 +63,7 @@ struct ShaderData { virtual void get_instance_param_list(List *p_param_list) const; virtual bool is_parameter_texture(const StringName &p_param) const; - virtual void set_code(const String &p_Code) = 0; + virtual void set_code(const String &p_Code, RID p_shader_template = RID()) = 0; virtual bool is_animated() const = 0; virtual bool casts_shadows() const = 0; virtual RS::ShaderNativeSourceCode get_native_source_code() const { return RS::ShaderNativeSourceCode(); } @@ -73,10 +73,19 @@ struct ShaderData { typedef ShaderData *(*ShaderDataRequestFunction)(); +struct Shader; struct Material; +struct ShaderTemplate { + ShaderGLES3 *shader; + HashSet owners; + + void cleanup(); +}; + struct Shader { ShaderData *data = nullptr; + RID shader_template; String code; String path_hint; RS::ShaderMode mode; @@ -172,7 +181,7 @@ struct CanvasShaderData : public ShaderData { uint64_t vertex_input_mask; - virtual void set_code(const String &p_Code); + virtual void set_code(const String &p_Code, RID p_shader_template = RID()); virtual bool is_animated() const; virtual bool casts_shadows() const; virtual RS::ShaderNativeSourceCode get_native_source_code() const; @@ -217,7 +226,7 @@ struct SkyShaderData : public ShaderData { bool uses_quarter_res; bool uses_light; - virtual void set_code(const String &p_Code); + virtual void set_code(const String &p_Code, RID p_shader_template = RID()); virtual bool is_animated() const; virtual bool casts_shadows() const; virtual RS::ShaderNativeSourceCode get_native_source_code() const; @@ -332,7 +341,7 @@ struct SceneShaderData : public ShaderData { uint64_t vertex_input_mask; - virtual void set_code(const String &p_Code); + virtual void set_code(const String &p_Code, RID p_shader_template = RID()); virtual bool is_animated() const; virtual bool casts_shadows() const; virtual RS::ShaderNativeSourceCode get_native_source_code() const; @@ -384,7 +393,7 @@ struct ParticlesShaderData : public ShaderData { bool userdatas_used[PARTICLES_MAX_USERDATAS] = {}; uint32_t userdata_count; - virtual void set_code(const String &p_Code); + virtual void set_code(const String &p_Code, RID p_shader_template = RID()); virtual bool is_animated() const; virtual bool casts_shadows() const; virtual RS::ShaderNativeSourceCode get_native_source_code() const; @@ -482,6 +491,10 @@ class MaterialStorage : public RendererMaterialStorage { /* SHADER API */ + mutable RID_Owner shader_template_owner; + + /* SHADER API */ + ShaderDataRequestFunction shader_data_request_func[RS::SHADER_MAX]; mutable RID_Owner shader_owner; @@ -574,6 +587,17 @@ class MaterialStorage : public RendererMaterialStorage { GLuint global_shader_parameters_get_uniform_buffer() const; + /* SHADER TEMPLATE API */ + + ShaderTemplate *get_shader_template(RID p_rid) { return shader_template_owner.get_or_null(p_rid); }; + bool owns_template_shader(RID p_rid) { return shader_template_owner.owns(p_rid); }; + + virtual RID shader_template_allocate() override; + virtual void shader_template_initialize(RID p_rid) override; + virtual void shader_template_free(RID p_rid) override; + + virtual void shader_template_set_raster_code(RID p_template_shader, const String &p_vertex_code, const String &p_fragment_code, const String &p_name) override; + /* SHADER API */ Shader *get_shader(RID p_rid) { return shader_owner.get_or_null(p_rid); }; @@ -585,6 +609,7 @@ class MaterialStorage : public RendererMaterialStorage { virtual void shader_initialize(RID p_rid) override; virtual void shader_free(RID p_rid) override; + virtual void shader_set_shader_template(RID p_shader, RID p_shader_template = RID(), bool p_clear_code = false) override; virtual void shader_set_code(RID p_shader, const String &p_code) override; virtual void shader_set_path_hint(RID p_shader, const String &p_path) override; virtual String shader_get_code(RID p_shader) const override; diff --git a/main/main.cpp b/main/main.cpp index 18ffedef1877..b28b013e7ccd 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -3447,6 +3447,10 @@ String Main::get_rendering_driver_name() { return rendering_driver; } +String Main::get_rendering_method() { + return rendering_method; +} + // everything the main loop needs to know about frame timings static MainTimerSync main_timer_sync; diff --git a/main/main.h b/main/main.h index 6dd2ff7d7a81..7350e1df33c7 100644 --- a/main/main.h +++ b/main/main.h @@ -73,6 +73,7 @@ class Main { static Error setup(const char *execpath, int argc, char *argv[], bool p_second_phase = true); static Error setup2(bool p_show_boot_logo = true); // The thread calling setup2() will effectively become the main thread. static String get_rendering_driver_name(); + static String get_rendering_method(); static void setup_boot_logo(); #ifdef TESTS_ENABLED static Error test_setup(); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 76678e609a9d..bcc72607949c 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -135,6 +135,7 @@ #include "scene/resources/portable_compressed_texture.h" #include "scene/resources/resource_format_text.h" #include "scene/resources/shader_include.h" +#include "scene/resources/shader_template.h" #include "scene/resources/skeleton_profile.h" #include "scene/resources/sky.h" #include "scene/resources/style_box.h" @@ -313,6 +314,9 @@ static Ref resource_loader_stream_textu static Ref resource_loader_texture_layered; static Ref resource_loader_texture_3d; +static Ref resource_saver_shader_template; +static Ref resource_loader_shader_template; + static Ref resource_saver_shader; static Ref resource_loader_shader; @@ -343,6 +347,12 @@ void register_scene_types() { resource_loader_text.instantiate(); ResourceLoader::add_resource_format_loader(resource_loader_text, true); + resource_saver_shader_template.instantiate(); + ResourceSaver::add_resource_format_saver(resource_saver_shader_template, true); + + resource_loader_shader_template.instantiate(); + ResourceLoader::add_resource_format_loader(resource_loader_shader_template, true); + resource_saver_shader.instantiate(); ResourceSaver::add_resource_format_saver(resource_saver_shader, true); @@ -642,6 +652,10 @@ void register_scene_types() { OS::get_singleton()->yield(); // may take time to init #endif // _3D_DISABLED + /* REGISTER SHADER TEMPLATE */ + + GDREGISTER_CLASS(ShaderTemplate); + /* REGISTER SHADER */ GDREGISTER_CLASS(Shader); @@ -1256,6 +1270,12 @@ void unregister_scene_types() { ResourceLoader::remove_resource_format_loader(resource_loader_text); resource_loader_text.unref(); + ResourceSaver::remove_resource_format_saver(resource_saver_shader_template); + resource_saver_shader_template.unref(); + + ResourceLoader::remove_resource_format_loader(resource_loader_shader_template); + resource_loader_shader_template.unref(); + ResourceSaver::remove_resource_format_saver(resource_saver_shader); resource_saver_shader.unref(); diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 927e76e4b2d0..10e9b6af4223 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -1869,6 +1869,13 @@ void fragment() {)"; shader_data.shader = RS::get_singleton()->shader_create(); shader_data.users = 1; + // Set shader template. + RID shader_template_rid; + if (shader_template.is_valid()) { + shader_template_rid = shader_template->get_rid(); + } + + RS::get_singleton()->shader_set_shader_template(shader_data.shader, shader_template_rid, true); RS::get_singleton()->shader_set_code(shader_data.shader, code); shader_map[mk] = shader_data; @@ -1893,6 +1900,19 @@ void BaseMaterial3D::_queue_shader_change() { } } +void BaseMaterial3D::set_shader_template(const Ref &p_shader_template) { + if (shader_template == p_shader_template) { + return; + } + + shader_template = p_shader_template; + _queue_shader_change(); +} + +Ref BaseMaterial3D::get_shader_template() const { + return shader_template; +} + void BaseMaterial3D::set_albedo(const Color &p_albedo) { albedo = p_albedo; @@ -2857,7 +2877,10 @@ Shader::Mode BaseMaterial3D::get_shader_mode() const { } void BaseMaterial3D::_bind_methods() { - static_assert(sizeof(MaterialKey) == 16, "MaterialKey should be 16 bytes"); + static_assert(sizeof(MaterialKey) == 24, "MaterialKey should be 24 bytes"); + + ClassDB::bind_method(D_METHOD("set_shader_template", "shader_template"), &BaseMaterial3D::set_shader_template); + ClassDB::bind_method(D_METHOD("get_shader_template"), &BaseMaterial3D::get_shader_template); ClassDB::bind_method(D_METHOD("set_albedo", "albedo"), &BaseMaterial3D::set_albedo); ClassDB::bind_method(D_METHOD("get_albedo"), &BaseMaterial3D::get_albedo); @@ -3075,6 +3098,7 @@ void BaseMaterial3D::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "no_depth_test"), "set_flag", "get_flag", FLAG_DISABLE_DEPTH_TEST); ADD_GROUP("Shading", ""); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shader_template", PROPERTY_HINT_RESOURCE_TYPE, "ShaderTemplate"), "set_shader_template", "get_shader_template"); ADD_PROPERTY(PropertyInfo(Variant::INT, "shading_mode", PROPERTY_HINT_ENUM, "Unshaded,Per-Pixel,Per-Vertex"), "set_shading_mode", "get_shading_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "diffuse_mode", PROPERTY_HINT_ENUM, "Burley,Lambert,Lambert Wrap,Toon"), "set_diffuse_mode", "get_diffuse_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "specular_mode", PROPERTY_HINT_ENUM, "SchlickGGX,Toon,Disabled"), "set_specular_mode", "get_specular_mode"); diff --git a/scene/resources/material.h b/scene/resources/material.h index 50a774e961f8..a185144fffd8 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -34,6 +34,7 @@ #include "core/io/resource.h" #include "core/templates/self_list.h" #include "scene/resources/shader.h" +#include "scene/resources/shader_template.h" #include "scene/resources/texture.h" #include "servers/rendering_server.h" @@ -339,6 +340,9 @@ class BaseMaterial3D : public Material { uint32_t feature_mask; uint32_t flags; + // shader template + uint64_t shader_template_id; + MaterialKey() { memset(this, 0, sizeof(MaterialKey)); } @@ -399,6 +403,12 @@ class BaseMaterial3D : public Material { } } + if (shader_template.is_valid()) { + mk.shader_template_id = shader_template->get_rid().get_id(); + } else { + mk.shader_template_id = 0; + } + return mk; } @@ -470,6 +480,8 @@ class BaseMaterial3D : public Material { bool orm; + Ref shader_template; + Color albedo; float specular = 0.0f; float metallic = 0.0f; @@ -565,6 +577,9 @@ class BaseMaterial3D : public Material { virtual bool _can_use_render_priority() const override { return true; } public: + void set_shader_template(const Ref &p_shader_template); + Ref get_shader_template() const; + void set_albedo(const Color &p_albedo); Color get_albedo() const; diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp index 46d38146a67f..c4b10cc1f520 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -32,9 +32,11 @@ #include "shader.compat.inc" #include "core/io/file_access.h" +#include "core/io/resource_loader.h" #include "servers/rendering/shader_language.h" #include "servers/rendering/shader_preprocessor.h" #include "servers/rendering_server.h" +#include "shader_template.h" #include "texture.h" #ifdef TOOLS_ENABLED @@ -114,6 +116,20 @@ void Shader::set_code(const String &p_code) { E->connect_changed(callable_mp(this, &Shader::_dependency_changed)); } + Ref new_shader_template; + + String shader_template_path = ShaderLanguage::get_shader_template(pp_code); + if (!shader_template_path.is_empty()) { + new_shader_template = ResourceLoader::load(shader_template_path); + } + if (shader_template != new_shader_template) { + shader_template = new_shader_template; + if (shader_template.is_valid()) { + RenderingServer::get_singleton()->shader_set_shader_template(shader, shader_template->get_rid(), true); + } else { + RenderingServer::get_singleton()->shader_set_shader_template(shader, RID()); + } + } RenderingServer::get_singleton()->shader_set_code(shader, pp_code); emit_changed(); diff --git a/scene/resources/shader.h b/scene/resources/shader.h index 682fbd7ea6a7..ba8054dee9cb 100644 --- a/scene/resources/shader.h +++ b/scene/resources/shader.h @@ -37,6 +37,8 @@ #include "scene/resources/texture.h" #include "shader_include.h" +class ShaderTemplate; + class Shader : public Resource { GDCLASS(Shader, Resource); OBJ_SAVE_TYPE(Shader); @@ -54,6 +56,7 @@ class Shader : public Resource { private: RID shader; Mode mode = MODE_SPATIAL; + Ref shader_template; HashSet> include_dependencies; String code; String include_path; diff --git a/scene/resources/shader_template.cpp b/scene/resources/shader_template.cpp new file mode 100644 index 000000000000..5c382f22f059 --- /dev/null +++ b/scene/resources/shader_template.cpp @@ -0,0 +1,249 @@ +/**************************************************************************/ +/* shader_template.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "shader_template.h" + +#include "main/main.h" +#include "servers/rendering_server.h" + +void ShaderTemplate::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_mode"), &ShaderTemplate::get_mode); + + ClassDB::bind_method(D_METHOD("set_code", "code"), &ShaderTemplate::set_code); + ClassDB::bind_method(D_METHOD("get_code"), &ShaderTemplate::get_code); + + ADD_PROPERTY(PropertyInfo(Variant::STRING, "code", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_code", "get_code"); +} + +void ShaderTemplate::_update_template() { + String shader_name = get_path(); + + if (shader_name.is_empty()) { + uint64_t id = shader_template.get_id(); + shader_name = "resource_" + String::num_uint64(id); + } else { + shader_name = shader_name.replace("res://", ""); + shader_name = shader_name.replace(".gdtemplate", ""); + shader_name = shader_name.replace("/", "_"); + shader_name = shader_name.to_camel_case(); + } + + int shader = -1; + mode = Shader::MODE_MAX; + String current_rendering_method = Main::get_rendering_method(); + bool is_current_rendering_method = true; // If no rendering method has been specified, we assume true. + String vertex_shader = ""; + String fragment_shader = ""; + + // Note, we only split out our vertex and fragment shader here. + // We do not process includes or compile the shaders. + // With templates this happens inside of the rendering engine! + + Vector lines = code.split("\n"); + String empty_lines; + String shader_type; + for (int lidx = 0; lidx < lines.size(); lidx++) { + String line = lines[lidx]; + if (line.begins_with("shader_type")) { + // Extract shader type + int end_pos = line.find(";"); + if (end_pos != -1) { + shader_type = line.substr(12, end_pos - 12); + } + } else if (line.begins_with("#[")) { + int pos = line.find("]"); + ERR_FAIL_COND_MSG(pos == -1, "Incomplete tag found in shader template - " + String::num_int64(lidx) + ": " + line); + + String tag = line.substr(2, pos - 2); + if (tag == "vertex") { + if (is_current_rendering_method) { + ERR_FAIL_COND_MSG(shader != -1, "Unexpected vertex shader in shader template - " + String::num_int64(lidx) + ": " + line); + shader = 0; + empty_lines = ""; + } + } else if (tag == "fragment") { + if (is_current_rendering_method) { + ERR_FAIL_COND_MSG(shader != 0, "Unexpected fragment shader in shader template - " + String::num_int64(lidx) + ": " + line); + shader = 1; + empty_lines = ""; + } + } else { + // Assume any other tag denotes our rendering method heading. + is_current_rendering_method = (tag == current_rendering_method); + } + } else if (line.is_empty()) { + // Remove any trailing empty lines + empty_lines += "\n"; + } else if (is_current_rendering_method) { + ERR_FAIL_COND_MSG(shader == -1, "Unexpected shader template code - " + String::num_int64(lidx) + ": " + line); + + if (shader == 0) { + vertex_shader += empty_lines + line + "\n"; + } else if (shader == 1) { + fragment_shader += empty_lines + line + "\n"; + } + empty_lines = ""; + } else { + // Skip this line, we're not handling the current rendering method + } + } + + if (shader_type == "canvas_item") { + mode = Shader::MODE_CANVAS_ITEM; + } else if (shader_type == "particles") { + mode = Shader::MODE_PARTICLES; + } else if (shader_type == "sky") { + mode = Shader::MODE_SKY; + } else if (shader_type == "fog") { + mode = Shader::MODE_FOG; + } else if (shader_type == "spatial") { + mode = Shader::MODE_SPATIAL; + } else { + ERR_FAIL_MSG("Unknown shader type in shader template."); + } + + ERR_FAIL_COND_MSG(vertex_shader.is_empty(), "No vertex shader code found for this shader template."); + ERR_FAIL_COND_MSG(fragment_shader.is_empty(), "No vertex shader code found for this shader template."); + + RenderingServer::get_singleton()->shader_template_set_raster_code(shader_template, vertex_shader, fragment_shader, shader_name); +} + +void ShaderTemplate::set_path(const String &p_path, bool p_take_over) { + Resource::set_path(p_path, p_take_over); + + _update_template(); +} + +Shader::Mode ShaderTemplate::get_mode() const { + return mode; +} + +String ShaderTemplate::get_code() const { + return code; +} + +void ShaderTemplate::set_code(const String &p_code) { + code = p_code; + + _update_template(); +} + +RID ShaderTemplate::get_rid() const { + return shader_template; +} + +ShaderTemplate::ShaderTemplate() { + shader_template = RenderingServer::get_singleton()->shader_template_create(); +} + +ShaderTemplate::~ShaderTemplate() { + ERR_FAIL_NULL(RenderingServer::get_singleton()); + RenderingServer::get_singleton()->free(shader_template); +} + +//////////// + +Ref ResourceFormatLoaderShaderTemplate::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { + if (r_error) { + *r_error = ERR_FILE_CANT_OPEN; + } + + Error error = OK; + Vector buffer = FileAccess::get_file_as_bytes(p_path, &error); + if (r_error) { + *r_error = error; + } + ERR_FAIL_COND_V_MSG(error, nullptr, "Cannot load shader: " + p_path); + + String str; + if (buffer.size() > 0) { + error = str.parse_utf8((const char *)buffer.ptr(), buffer.size()); + if (r_error) { + *r_error = error; + } + ERR_FAIL_COND_V_MSG(error, nullptr, "Cannot parse shader: " + p_path); + } + + Ref shader_template; + shader_template.instantiate(); + shader_template->set_code(str); + + if (r_error) { + *r_error = OK; + } + + return shader_template; +} + +void ResourceFormatLoaderShaderTemplate::get_recognized_extensions(List *p_extensions) const { + p_extensions->push_back("gdtemplate"); +} + +bool ResourceFormatLoaderShaderTemplate::handles_type(const String &p_type) const { + return (p_type == "ShaderTemplate"); +} + +String ResourceFormatLoaderShaderTemplate::get_resource_type(const String &p_path) const { + String el = p_path.get_extension().to_lower(); + if (el == "gdtemplate") { + return "ShaderTemplate"; + } + return ""; +} + +Error ResourceFormatSaverShaderTemplate::save(const Ref &p_resource, const String &p_path, uint32_t p_flags) { + Ref shader_template = p_resource; + ERR_FAIL_COND_V(shader_template.is_null(), ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(shader_template->get_mode() >= Shader::MODE_MAX, ERR_INVALID_DATA); + + String code = shader_template->get_code(); + + Error err; + Ref file = FileAccess::open(p_path, FileAccess::WRITE, &err); + + ERR_FAIL_COND_V_MSG(err, err, "Cannot save shader template '" + p_path + "'."); + + file->store_string(code); + if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) { + return ERR_CANT_CREATE; + } + + return OK; +} + +void ResourceFormatSaverShaderTemplate::get_recognized_extensions(const Ref &p_resource, List *p_extensions) const { + if (Object::cast_to(*p_resource)) { + p_extensions->push_back("gdtemplate"); + } +} + +bool ResourceFormatSaverShaderTemplate::recognize(const Ref &p_resource) const { + return p_resource->get_class_name() == "ShaderTemplate"; +} diff --git a/scene/resources/shader_template.h b/scene/resources/shader_template.h new file mode 100644 index 000000000000..e7b04b76be37 --- /dev/null +++ b/scene/resources/shader_template.h @@ -0,0 +1,82 @@ +/**************************************************************************/ +/* shader_template.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef SHADER_TEMPLATE_H +#define SHADER_TEMPLATE_H + +#include "core/io/resource.h" +#include "core/io/resource_loader.h" +#include "core/io/resource_saver.h" +#include "shader.h" + +class ShaderTemplate : public Resource { + GDCLASS(ShaderTemplate, Resource); + +private: + RID shader_template; + + Shader::Mode mode = Shader::MODE_SPATIAL; + String code; + + void _update_template(); + +protected: + static void _bind_methods(); + +public: + virtual void set_path(const String &p_path, bool p_take_over = false) override; + + Shader::Mode get_mode() const; + + String get_code() const; + void set_code(const String &p_code); + + virtual RID get_rid() const override; + + ShaderTemplate(); + ~ShaderTemplate(); +}; + +class ResourceFormatLoaderShaderTemplate : public ResourceFormatLoader { +public: + virtual Ref load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override; + virtual void get_recognized_extensions(List *p_extensions) const override; + virtual bool handles_type(const String &p_type) const override; + virtual String get_resource_type(const String &p_path) const override; +}; + +class ResourceFormatSaverShaderTemplate : public ResourceFormatSaver { +public: + virtual Error save(const Ref &p_resource, const String &p_path, uint32_t p_flags = 0) override; + virtual void get_recognized_extensions(const Ref &p_resource, List *p_extensions) const override; + virtual bool recognize(const Ref &p_resource) const override; +}; + +#endif // SHADER_TEMPLATE_H diff --git a/servers/rendering/dummy/storage/material_storage.h b/servers/rendering/dummy/storage/material_storage.h index 4a956cd25d08..4a17d20eabfc 100644 --- a/servers/rendering/dummy/storage/material_storage.h +++ b/servers/rendering/dummy/storage/material_storage.h @@ -74,6 +74,14 @@ class MaterialStorage : public RendererMaterialStorage { virtual void global_shader_parameters_instance_free(RID p_instance) override {} virtual void global_shader_parameters_instance_update(RID p_instance, int p_index, const Variant &p_value, int p_flags_count = 0) override {} + /* SHADER TEMPLATE API */ + + virtual RID shader_template_allocate() override { return RID(); } + virtual void shader_template_initialize(RID p_rid) override {} + virtual void shader_template_free(RID p_rid) override {} + + virtual void shader_template_set_raster_code(RID p_template_shader, const String &p_vertex_code, const String &p_fragment_code, const String &p_name) override{}; + /* SHADER API */ bool owns_shader(RID p_rid) { return shader_owner.owns(p_rid); } @@ -82,6 +90,7 @@ class MaterialStorage : public RendererMaterialStorage { virtual void shader_initialize(RID p_rid) override; virtual void shader_free(RID p_rid) override; + virtual void shader_set_shader_template(RID p_shader, RID p_shader_template = RID(), bool p_clear_code = false) override {} virtual void shader_set_code(RID p_shader, const String &p_code) override; virtual void shader_set_path_hint(RID p_shader, const String &p_code) override {} diff --git a/servers/rendering/renderer_rd/environment/fog.cpp b/servers/rendering/renderer_rd/environment/fog.cpp index 2dfcd6741168..843d85b0a53d 100644 --- a/servers/rendering/renderer_rd/environment/fog.cpp +++ b/servers/rendering/renderer_rd/environment/fog.cpp @@ -311,7 +311,12 @@ void Fog::free_fog_shader() { } } -void Fog::FogShaderData::set_code(const String &p_code) { +void Fog::FogShaderData::set_code(const String &p_code, RID p_shader_template) { + // Shader template isn't supported here yet. + if (p_shader_template.is_valid()) { + WARN_PRINT_ONCE("Shader templates are not supported for fog shaders."); + } + //compile code = p_code; diff --git a/servers/rendering/renderer_rd/environment/fog.h b/servers/rendering/renderer_rd/environment/fog.h index 25fb190f444c..4059b6e2011c 100644 --- a/servers/rendering/renderer_rd/environment/fog.h +++ b/servers/rendering/renderer_rd/environment/fog.h @@ -199,7 +199,7 @@ class Fog : public RendererFog { bool uses_time = false; - virtual void set_code(const String &p_Code); + virtual void set_code(const String &p_Code, RID p_shader_template = RID()); virtual bool is_animated() const; virtual bool casts_shadows() const; virtual RS::ShaderNativeSourceCode get_native_source_code() const; diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp index 208798910269..cb58c995e24a 100644 --- a/servers/rendering/renderer_rd/environment/sky.cpp +++ b/servers/rendering/renderer_rd/environment/sky.cpp @@ -51,7 +51,12 @@ using namespace RendererRD; //////////////////////////////////////////////////////////////////////////////// // SKY SHADER -void SkyRD::SkyShaderData::set_code(const String &p_code) { +void SkyRD::SkyShaderData::set_code(const String &p_code, RID p_shader_template) { + // Shader template isn't supported here yet. + if (p_shader_template.is_valid()) { + WARN_PRINT_ONCE("Shader templates are not supported for sky shaders."); + } + //compile code = p_code; diff --git a/servers/rendering/renderer_rd/environment/sky.h b/servers/rendering/renderer_rd/environment/sky.h index b146a416f9b8..ce43cfb8b915 100644 --- a/servers/rendering/renderer_rd/environment/sky.h +++ b/servers/rendering/renderer_rd/environment/sky.h @@ -123,7 +123,7 @@ class SkyRD { bool uses_quarter_res = false; bool uses_light = false; - virtual void set_code(const String &p_Code); + virtual void set_code(const String &p_Code, RID p_shader_template = RID()); virtual bool is_animated() const; virtual bool casts_shadows() const; virtual RS::ShaderNativeSourceCode get_native_source_code() const; diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index 36bd22b7234f..d502c20b9bba 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -33,6 +33,10 @@ #include "core/object/worker_thread_pool.h" #include "servers/rendering/renderer_rd/framebuffer_cache_rd.h" #include "servers/rendering/renderer_rd/renderer_compositor_rd.h" +#include "servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_input_attributes_inc.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_output_buffers_inc.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_specialization_constants_inc.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_standard_inc.glsl.gen.h" #include "servers/rendering/renderer_rd/storage_rd/light_storage.h" #include "servers/rendering/renderer_rd/storage_rd/mesh_storage.h" #include "servers/rendering/renderer_rd/storage_rd/particles_storage.h" @@ -1730,7 +1734,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co if (p_render_data->scene_data->view_count > 1) { color_pass_flags |= COLOR_PASS_FLAG_MULTIVIEW; // Try enabling here in case is_xr_enabled() returns false. - scene_shader.shader.enable_group(SceneShaderForwardClustered::SHADER_GROUP_MULTIVIEW); + RendererRD::MaterialStorage::get_singleton()->shader_template_enable_group_on_all(SceneShaderForwardClustered::SHADER_GROUP_MULTIVIEW); } color_framebuffer = rb_data->get_color_pass_fb(color_pass_flags); @@ -4263,6 +4267,13 @@ void RenderForwardClustered::_update_shader_quality_settings() { RenderForwardClustered::RenderForwardClustered() { singleton = this; + /* INCLUDE FILES */ + + RenderingDevice::register_built_in_include_file("standard_includes.glsl", scene_forward_clustered_standard_inc_shader_glsl); + RenderingDevice::register_built_in_include_file("input_attributes.glsl", scene_forward_clustered_input_attributes_inc_shader_glsl); + RenderingDevice::register_built_in_include_file("specialization_constants.glsl", scene_forward_clustered_specialization_constants_inc_shader_glsl); + RenderingDevice::register_built_in_include_file("output_buffers.glsl", scene_forward_clustered_output_buffers_inc_shader_glsl); + /* SCENE SHADER */ { diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp index 6846c3f693fe..ea2ea751677d 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp @@ -37,7 +37,68 @@ using namespace RendererSceneRenderImplementation; -void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { +void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code, RID p_shader_template) { + // get shader template + SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton; + RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); + + shader_template = p_shader_template; + if (shader_template.is_null()) { + shader_template = shader_singleton->default_shader_template; + } + ERR_FAIL_COND(shader_template.is_null()); + + if (!material_storage->shader_template_is_initialized(shader_template)) { + // For our default template shader, this will be called when our default material gets created. + + Vector shader_versions; + shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_BASE, "\n#define MODE_RENDER_DEPTH\n", true)); // SHADER_VERSION_DEPTH_PASS + shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_BASE, "\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n", true)); // SHADER_VERSION_DEPTH_PASS_DP + shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_BASE, "\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n", true)); // SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS + shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_ADVANCED, "\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n#define MODE_RENDER_VOXEL_GI\n", false)); // SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI + shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_ADVANCED, "\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n", false)); // SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL + shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_ADVANCED, "\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_SDF\n", false)); // SHADER_VERSION_DEPTH_PASS_WITH_SDF + shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_MULTIVIEW, "\n#define USE_MULTIVIEW\n#define MODE_RENDER_DEPTH\n", false)); // SHADER_VERSION_DEPTH_PASS_MULTIVIEW + shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_MULTIVIEW, "\n#define USE_MULTIVIEW\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n", false)); // SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_MULTIVIEW + shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_MULTIVIEW, "\n#define USE_MULTIVIEW\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n#define MODE_RENDER_VOXEL_GI\n", false)); // SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI_MULTIVIEW + + Vector color_pass_flags = { + "\n#define MODE_SEPARATE_SPECULAR\n", // SHADER_COLOR_PASS_FLAG_SEPARATE_SPECULAR + "\n#define USE_LIGHTMAP\n", // SHADER_COLOR_PASS_FLAG_LIGHTMAP + "\n#define USE_MULTIVIEW\n", // SHADER_COLOR_PASS_FLAG_MULTIVIEW + "\n#define MOTION_VECTORS\n", // SHADER_COLOR_PASS_FLAG_MOTION_VECTORS + }; + + for (int i = 0; i < SHADER_COLOR_PASS_FLAG_COUNT; i++) { + String versions = ""; + for (int j = 0; (1 << j) < SHADER_COLOR_PASS_FLAG_COUNT; j += 1) { + if ((1 << j) & i) { + versions += color_pass_flags[j]; + } + } + + // Assign a group based on what features this pass contains. + ShaderGroup group = SHADER_GROUP_BASE; + bool advanced_group = (i & SHADER_COLOR_PASS_FLAG_SEPARATE_SPECULAR) || (i & SHADER_COLOR_PASS_FLAG_LIGHTMAP) || (i & SHADER_COLOR_PASS_FLAG_MOTION_VECTORS); + bool multiview_group = i & SHADER_COLOR_PASS_FLAG_MULTIVIEW; + if (advanced_group && multiview_group) { + group = SHADER_GROUP_ADVANCED_MULTIVIEW; + } else if (advanced_group) { + group = SHADER_GROUP_ADVANCED; + } else if (multiview_group) { + group = SHADER_GROUP_MULTIVIEW; + } + + shader_versions.push_back(ShaderRD::VariantDefine(group, versions, false)); + } + + material_storage->shader_template_initialize(shader_template, shader_versions, shader_singleton->default_defines); + + if (RendererCompositorRD::get_singleton()->is_xr_enabled()) { + material_storage->shader_template_enable_group(shader_template, SHADER_GROUP_MULTIVIEW); + } + } + //compile code = p_code; @@ -141,12 +202,11 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { actions.uniforms = &uniforms; - SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton; Error err = shader_singleton->compiler.compile(RS::SHADER_SPATIAL, code, &actions, path, gen_code); ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed."); if (version.is_null()) { - version = shader_singleton->shader.version_create(); + version = material_storage->shader_template_version_create(shader_template); } depth_draw = DepthDraw(depth_drawi); @@ -178,8 +238,8 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { print_line("\n**vertex_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX]); print_line("\n**fragment_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT]); #endif - shader_singleton->shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines); - ERR_FAIL_COND(!shader_singleton->shader.version_is_valid(version)); + material_storage->shader_template_version_set_code(shader_template, version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines); + ERR_FAIL_COND(!material_storage->shader_template_version_is_valid(shader_template, version)); ubo_size = gen_code.uniform_total_size; ubo_offsets = gen_code.uniform_offsets; @@ -313,7 +373,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { shader_version = shader_version_table[k]; - if (!static_cast(singleton)->shader.is_variant_enabled(shader_version)) { + if (!material_storage->shader_template_is_variant_enabled(shader_template, shader_version)) { continue; } RD::PipelineRasterizationState raster_state; @@ -375,11 +435,11 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { int variant = shader_version + shader_flags; - if (!static_cast(singleton)->shader.is_variant_enabled(variant)) { + if (!material_storage->shader_template_is_variant_enabled(shader_template, variant)) { continue; } - RID shader_variant = shader_singleton->shader.version_get_shader(version, variant); + RID shader_variant = material_storage->shader_template_version_get_shader(shader_template, version, variant); color_pipelines[i][j][l].setup(shader_variant, primitive_rd, raster_state, multisample_state, depth_stencil, blend_state, 0, singleton->default_specialization_constants); } } else { @@ -399,7 +459,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { blend_state = RD::PipelineColorBlendState(); //no color targets for SDF } - RID shader_variant = shader_singleton->shader.version_get_shader(version, shader_version); + RID shader_variant = material_storage->shader_template_version_get_shader(shader_template, version, shader_version); pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, multisample_state, depth_stencil, blend_state, 0, singleton->default_specialization_constants); } } @@ -422,9 +482,9 @@ bool SceneShaderForwardClustered::ShaderData::casts_shadows() const { } RS::ShaderNativeSourceCode SceneShaderForwardClustered::ShaderData::get_native_source_code() const { - SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton; + RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); - return shader_singleton->shader.version_get_native_source_code(version); + return material_storage->shader_template_version_get_native_source_code(shader_template, version); } SceneShaderForwardClustered::ShaderData::ShaderData() : @@ -432,11 +492,12 @@ SceneShaderForwardClustered::ShaderData::ShaderData() : } SceneShaderForwardClustered::ShaderData::~ShaderData() { - SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton; - ERR_FAIL_NULL(shader_singleton); + RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); + ERR_FAIL_NULL(material_storage); + //pipeline variants will clear themselves if shader is gone if (version.is_valid()) { - shader_singleton->shader.version_free(version); + material_storage->shader_template_version_free(shader_template, version); } } @@ -455,9 +516,9 @@ void SceneShaderForwardClustered::MaterialData::set_next_pass(RID p_pass) { } bool SceneShaderForwardClustered::MaterialData::update_parameters(const HashMap &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { - SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton; + RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); - return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardClustered::MATERIAL_UNIFORM_SET, true, true); + return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, material_storage->shader_template_version_get_shader(shader_data->shader_template, shader_data->version, 0), RenderForwardClustered::MATERIAL_UNIFORM_SET, true, true); } SceneShaderForwardClustered::MaterialData::~MaterialData() { @@ -491,58 +552,18 @@ SceneShaderForwardClustered::~SceneShaderForwardClustered() { material_storage->material_free(overdraw_material); material_storage->material_free(default_material); material_storage->material_free(debug_shadow_splits_material); + + material_storage->shader_template_free(default_shader_template); } void SceneShaderForwardClustered::init(const String p_defines) { RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); { - Vector shader_versions; - shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_BASE, "\n#define MODE_RENDER_DEPTH\n", true)); // SHADER_VERSION_DEPTH_PASS - shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_BASE, "\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n", true)); // SHADER_VERSION_DEPTH_PASS_DP - shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_BASE, "\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n", true)); // SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS - shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_ADVANCED, "\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n#define MODE_RENDER_VOXEL_GI\n", false)); // SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI - shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_ADVANCED, "\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n", false)); // SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL - shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_ADVANCED, "\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_SDF\n", false)); // SHADER_VERSION_DEPTH_PASS_WITH_SDF - shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_MULTIVIEW, "\n#define USE_MULTIVIEW\n#define MODE_RENDER_DEPTH\n", false)); // SHADER_VERSION_DEPTH_PASS_MULTIVIEW - shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_MULTIVIEW, "\n#define USE_MULTIVIEW\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n", false)); // SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_MULTIVIEW - shader_versions.push_back(ShaderRD::VariantDefine(SHADER_GROUP_MULTIVIEW, "\n#define USE_MULTIVIEW\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n#define MODE_RENDER_VOXEL_GI\n", false)); // SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI_MULTIVIEW - - Vector color_pass_flags = { - "\n#define MODE_SEPARATE_SPECULAR\n", // SHADER_COLOR_PASS_FLAG_SEPARATE_SPECULAR - "\n#define USE_LIGHTMAP\n", // SHADER_COLOR_PASS_FLAG_LIGHTMAP - "\n#define USE_MULTIVIEW\n", // SHADER_COLOR_PASS_FLAG_MULTIVIEW - "\n#define MOTION_VECTORS\n", // SHADER_COLOR_PASS_FLAG_MOTION_VECTORS - }; - - for (int i = 0; i < SHADER_COLOR_PASS_FLAG_COUNT; i++) { - String version = ""; - for (int j = 0; (1 << j) < SHADER_COLOR_PASS_FLAG_COUNT; j += 1) { - if ((1 << j) & i) { - version += color_pass_flags[j]; - } - } - - // Assign a group based on what features this pass contains. - ShaderGroup group = SHADER_GROUP_BASE; - bool advanced_group = (i & SHADER_COLOR_PASS_FLAG_SEPARATE_SPECULAR) || (i & SHADER_COLOR_PASS_FLAG_LIGHTMAP) || (i & SHADER_COLOR_PASS_FLAG_MOTION_VECTORS); - bool multiview_group = i & SHADER_COLOR_PASS_FLAG_MULTIVIEW; - if (advanced_group && multiview_group) { - group = SHADER_GROUP_ADVANCED_MULTIVIEW; - } else if (advanced_group) { - group = SHADER_GROUP_ADVANCED; - } else if (multiview_group) { - group = SHADER_GROUP_MULTIVIEW; - } - - shader_versions.push_back(ShaderRD::VariantDefine(group, version, false)); - } - - shader.initialize(shader_versions, p_defines); - - if (RendererCompositorRD::get_singleton()->is_xr_enabled()) { - shader.enable_group(SHADER_GROUP_MULTIVIEW); - } + default_defines = p_defines; + default_shader_template = material_storage->shader_template_allocate(); + material_storage->shader_template_initialize(default_shader_template); + material_storage->shader_template_set_shader(default_shader_template, memnew(SceneForwardClusteredShaderRD)); } // Set flag to true if a combination is valid. @@ -772,8 +793,8 @@ void fragment() { material_storage->material_set_shader(default_material, default_shader); MaterialData *md = static_cast(material_storage->material_get_data(default_material, RendererRD::MaterialStorage::SHADER_TYPE_3D)); - default_shader_rd = shader.version_get_shader(md->shader_data->version, SHADER_VERSION_COLOR_PASS); - default_shader_sdfgi_rd = shader.version_get_shader(md->shader_data->version, SHADER_VERSION_DEPTH_PASS_WITH_SDF); + default_shader_rd = material_storage->shader_template_version_get_shader(default_shader_template, md->shader_data->version, SHADER_VERSION_COLOR_PASS); + default_shader_sdfgi_rd = material_storage->shader_template_version_get_shader(default_shader_template, md->shader_data->version, SHADER_VERSION_DEPTH_PASS_WITH_SDF); default_material_shader_ptr = md->shader_data; default_material_uniform_set = md->uniform_set; @@ -865,8 +886,10 @@ void SceneShaderForwardClustered::set_default_specialization_constants(const Vec } void SceneShaderForwardClustered::enable_advanced_shader_group(bool p_needs_multiview) { + RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); + if (p_needs_multiview || RendererCompositorRD::get_singleton()->is_xr_enabled()) { - shader.enable_group(SHADER_GROUP_ADVANCED_MULTIVIEW); + material_storage->shader_template_enable_group_on_all(SHADER_GROUP_ADVANCED_MULTIVIEW); } - shader.enable_group(SHADER_GROUP_ADVANCED); + material_storage->shader_template_enable_group_on_all(SHADER_GROUP_ADVANCED); } diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h index d5332032f9f0..c1782d7e6743 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h @@ -142,6 +142,7 @@ class SceneShaderForwardClustered { }; bool valid = false; + RID shader_template; RID version; uint64_t vertex_input_mask = 0; PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][PIPELINE_VERSION_MAX]; @@ -188,7 +189,7 @@ class SceneShaderForwardClustered { uint64_t last_pass = 0; uint32_t index = 0; - virtual void set_code(const String &p_Code); + virtual void set_code(const String &p_Code, RID p_shader_template = RID()); virtual bool is_animated() const; virtual bool casts_shadows() const; @@ -224,9 +225,10 @@ class SceneShaderForwardClustered { return static_cast(singleton)->_create_material_func(static_cast(p_shader)); } - SceneForwardClusteredShaderRD shader; + String default_defines; ShaderCompiler compiler; + RID default_shader_template; RID default_shader; RID default_material; RID overdraw_material_shader; diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index 48c226133d39..84962a474394 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -31,6 +31,10 @@ #include "render_forward_mobile.h" #include "core/config/project_settings.h" #include "core/object/worker_thread_pool.h" +#include "servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_input_attributes_inc.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_output_buffers_inc.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_specialization_constants_inc.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_standard_inc.glsl.gen.h" #include "servers/rendering/renderer_rd/storage_rd/light_storage.h" #include "servers/rendering/renderer_rd/storage_rd/mesh_storage.h" #include "servers/rendering/renderer_rd/storage_rd/particles_storage.h" @@ -2801,16 +2805,29 @@ void RenderForwardMobile::_update_shader_quality_settings() { RenderForwardMobile::RenderForwardMobile() { singleton = this; + /* INCLUDE FILES */ + + RenderingDevice::register_built_in_include_file("standard_includes.glsl", scene_forward_mobile_standard_inc_shader_glsl); + RenderingDevice::register_built_in_include_file("input_attributes.glsl", scene_forward_mobile_input_attributes_inc_shader_glsl); + RenderingDevice::register_built_in_include_file("specialization_constants.glsl", scene_forward_mobile_specialization_constants_inc_shader_glsl); + RenderingDevice::register_built_in_include_file("output_buffers.glsl", scene_forward_mobile_output_buffers_inc_shader_glsl); + + /* SKY SHADER */ + sky.set_texture_format(_render_buffers_get_color_format()); + /* SCENE SHADER */ + String defines; - defines += "\n#define MAX_ROUGHNESS_LOD " + itos(get_roughness_layers() - 1) + ".0\n"; - if (is_using_radiance_cubemap_array()) { - defines += "\n#define USE_RADIANCE_CUBEMAP_ARRAY \n"; + { + defines += "\n#define MAX_ROUGHNESS_LOD " + itos(get_roughness_layers() - 1) + ".0\n"; + if (is_using_radiance_cubemap_array()) { + defines += "\n#define USE_RADIANCE_CUBEMAP_ARRAY \n"; + } + // defines += "\n#define SDFGI_OCT_SIZE " + itos(gi.sdfgi_get_lightprobe_octahedron_size()) + "\n"; + defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(MAX_DIRECTIONAL_LIGHTS) + "\n"; } - // defines += "\n#define SDFGI_OCT_SIZE " + itos(gi.sdfgi_get_lightprobe_octahedron_size()) + "\n"; - defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(MAX_DIRECTIONAL_LIGHTS) + "\n"; { //lightmaps diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp index 08982096c566..2961fc860c3a 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp @@ -39,7 +39,39 @@ using namespace RendererSceneRenderImplementation; /* ShaderData */ -void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { +void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code, RID p_shader_template) { + // get shader template + SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton; + RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); + + shader_template = p_shader_template; + if (shader_template.is_null()) { + shader_template = shader_singleton->default_shader_template; + } + ERR_FAIL_COND(shader_template.is_null()); + + if (!material_storage->shader_template_is_initialized(shader_template)) { + Vector shader_versions; + shader_versions.push_back(""); // SHADER_VERSION_COLOR_PASS + shader_versions.push_back("\n#define USE_LIGHTMAP\n"); // SHADER_VERSION_LIGHTMAP_COLOR_PASS + shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n"); // SHADER_VERSION_SHADOW_PASS, should probably change this to MODE_RENDER_SHADOW because we don't have a depth pass here... + shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n"); // SHADER_VERSION_SHADOW_PASS_DP + shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n"); // SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL + + // multiview versions of our shaders + shader_versions.push_back("\n#define USE_MULTIVIEW\n"); // SHADER_VERSION_COLOR_PASS_MULTIVIEW + shader_versions.push_back("\n#define USE_MULTIVIEW\n#define USE_LIGHTMAP\n"); // SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW + shader_versions.push_back("\n#define USE_MULTIVIEW\n#define MODE_RENDER_DEPTH\n"); // SHADER_VERSION_SHADOW_PASS_MULTIVIEW + + material_storage->shader_template_initialize(shader_template, shader_versions, shader_singleton->default_defines); + + if (!RendererCompositorRD::get_singleton()->is_xr_enabled()) { + material_storage->shader_template_set_variant_enabled(shader_template, SHADER_VERSION_COLOR_PASS_MULTIVIEW, false); + material_storage->shader_template_set_variant_enabled(shader_template, SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW, false); + material_storage->shader_template_set_variant_enabled(shader_template, SHADER_VERSION_SHADOW_PASS_MULTIVIEW, false); + } + } + //compile code = p_code; @@ -141,13 +173,11 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { actions.uniforms = &uniforms; - SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton; - Error err = shader_singleton->compiler.compile(RS::SHADER_SPATIAL, code, &actions, path, gen_code); ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed."); if (version.is_null()) { - version = shader_singleton->shader.version_create(); + version = material_storage->shader_template_version_create(shader_template); } depth_draw = DepthDraw(depth_drawi); @@ -189,8 +219,8 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { print_line("\n**fragment_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT]); #endif - shader_singleton->shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines); - ERR_FAIL_COND(!shader_singleton->shader.version_is_valid(version)); + material_storage->shader_template_version_set_code(shader_template, version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines); + ERR_FAIL_COND(!material_storage->shader_template_version_is_valid(shader_template, version)); ubo_size = gen_code.uniform_total_size; ubo_offsets = gen_code.uniform_offsets; @@ -307,7 +337,7 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { RD::RenderPrimitive primitive_rd = uses_point_size ? RD::RENDER_PRIMITIVE_POINTS : primitive_rd_table[j]; for (int k = 0; k < SHADER_VERSION_MAX; k++) { - if (!static_cast(singleton)->shader.is_variant_enabled(k)) { + if (!material_storage->shader_template_is_variant_enabled(shader_template, k)) { continue; } RD::PipelineRasterizationState raster_state; @@ -352,7 +382,7 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { } } - RID shader_variant = shader_singleton->shader.version_get_shader(version, k); + RID shader_variant = material_storage->shader_template_version_get_shader(shader_template, version, k); pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, multisample_state, depth_stencil, blend_state, 0, singleton->default_specialization_constants); } } @@ -374,9 +404,9 @@ bool SceneShaderForwardMobile::ShaderData::casts_shadows() const { } RS::ShaderNativeSourceCode SceneShaderForwardMobile::ShaderData::get_native_source_code() const { - SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton; + RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); - return shader_singleton->shader.version_get_native_source_code(version); + return material_storage->shader_template_version_get_native_source_code(shader_template, version); } SceneShaderForwardMobile::ShaderData::ShaderData() : @@ -384,11 +414,12 @@ SceneShaderForwardMobile::ShaderData::ShaderData() : } SceneShaderForwardMobile::ShaderData::~ShaderData() { - SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton; - ERR_FAIL_NULL(shader_singleton); + RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); + ERR_FAIL_NULL(material_storage); + //pipeline variants will clear themselves if shader is gone if (version.is_valid()) { - shader_singleton->shader.version_free(version); + material_storage->shader_template_version_free(shader_template, version); } } @@ -407,9 +438,9 @@ void SceneShaderForwardMobile::MaterialData::set_next_pass(RID p_pass) { } bool SceneShaderForwardMobile::MaterialData::update_parameters(const HashMap &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { - SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton; + RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton(); - return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardMobile::MATERIAL_UNIFORM_SET, true, true); + return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, material_storage->shader_template_version_get_shader(shader_data->shader_template, shader_data->version, 0), RenderForwardMobile::MATERIAL_UNIFORM_SET, true, true); } SceneShaderForwardMobile::MaterialData::~MaterialData() { @@ -438,25 +469,10 @@ void SceneShaderForwardMobile::init(const String p_defines) { /* SCENE SHADER */ { - Vector shader_versions; - shader_versions.push_back(""); // SHADER_VERSION_COLOR_PASS - shader_versions.push_back("\n#define USE_LIGHTMAP\n"); // SHADER_VERSION_LIGHTMAP_COLOR_PASS - shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n"); // SHADER_VERSION_SHADOW_PASS, should probably change this to MODE_RENDER_SHADOW because we don't have a depth pass here... - shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n"); // SHADER_VERSION_SHADOW_PASS_DP - shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n"); // SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL - - // multiview versions of our shaders - shader_versions.push_back("\n#define USE_MULTIVIEW\n"); // SHADER_VERSION_COLOR_PASS_MULTIVIEW - shader_versions.push_back("\n#define USE_MULTIVIEW\n#define USE_LIGHTMAP\n"); // SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW - shader_versions.push_back("\n#define USE_MULTIVIEW\n#define MODE_RENDER_DEPTH\n"); // SHADER_VERSION_SHADOW_PASS_MULTIVIEW - - shader.initialize(shader_versions, p_defines); - - if (!RendererCompositorRD::get_singleton()->is_xr_enabled()) { - shader.set_variant_enabled(SHADER_VERSION_COLOR_PASS_MULTIVIEW, false); - shader.set_variant_enabled(SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW, false); - shader.set_variant_enabled(SHADER_VERSION_SHADOW_PASS_MULTIVIEW, false); - } + default_defines = p_defines; + default_shader_template = material_storage->shader_template_allocate(); + material_storage->shader_template_initialize(default_shader_template); + material_storage->shader_template_set_shader(default_shader_template, memnew(SceneForwardMobileShaderRD)); } material_storage->shader_set_data_request_function(RendererRD::MaterialStorage::SHADER_TYPE_3D, _create_shader_funcs); @@ -676,7 +692,7 @@ void fragment() { material_storage->material_set_shader(default_material, default_shader); MaterialData *md = static_cast(material_storage->material_get_data(default_material, RendererRD::MaterialStorage::SHADER_TYPE_3D)); - default_shader_rd = shader.version_get_shader(md->shader_data->version, SHADER_VERSION_COLOR_PASS); + default_shader_rd = material_storage->shader_template_version_get_shader(default_shader_template, md->shader_data->version, SHADER_VERSION_COLOR_PASS); default_material_shader_ptr = md->shader_data; default_material_uniform_set = md->uniform_set; @@ -778,4 +794,6 @@ SceneShaderForwardMobile::~SceneShaderForwardMobile() { material_storage->material_free(overdraw_material); material_storage->material_free(default_material); material_storage->material_free(debug_shadow_splits_material); + + material_storage->shader_template_free(default_shader_template); } diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h index 833b06c1e31b..46c2cc161793 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h @@ -97,6 +97,7 @@ class SceneShaderForwardMobile { }; bool valid = false; + RID shader_template; RID version; uint64_t vertex_input_mask = 0; PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][SHADER_VERSION_MAX]; @@ -140,7 +141,7 @@ class SceneShaderForwardMobile { uint64_t last_pass = 0; uint32_t index = 0; - virtual void set_code(const String &p_Code); + virtual void set_code(const String &p_Code, RID p_shader_template = RID()); virtual bool is_animated() const; virtual bool casts_shadows() const; virtual RS::ShaderNativeSourceCode get_native_source_code() const; @@ -176,9 +177,10 @@ class SceneShaderForwardMobile { return static_cast(singleton)->_create_material_func(static_cast(p_shader)); } - SceneForwardMobileShaderRD shader; + String default_defines; ShaderCompiler compiler; + RID default_shader_template; RID default_shader; RID default_material; RID overdraw_material_shader; diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index f51b4ae8d0f9..dcef56d9766f 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -2165,7 +2165,12 @@ void RendererCanvasRenderRD::occluder_polygon_set_cull_mode(RID p_occluder, RS:: oc->cull_mode = p_mode; } -void RendererCanvasRenderRD::CanvasShaderData::set_code(const String &p_code) { +void RendererCanvasRenderRD::CanvasShaderData::set_code(const String &p_code, RID p_shader_template) { + // Shader template isn't supported here yet. + if (p_shader_template.is_valid()) { + WARN_PRINT_ONCE("Shader templates are not supported for Canvas shaders."); + } + //compile code = p_code; diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h index 9deb4814c71d..a5a4419f3534 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h @@ -179,7 +179,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender { bool uses_sdf = false; bool uses_time = false; - virtual void set_code(const String &p_Code); + virtual void set_code(const String &p_Code, RID p_shader_template = RID()); virtual bool is_animated() const; virtual bool casts_shadows() const; virtual RS::ShaderNativeSourceCode get_native_source_code() const; diff --git a/servers/rendering/renderer_rd/shader_rd.h b/servers/rendering/renderer_rd/shader_rd.h index 22a21086af9d..3e6c404dbfb7 100644 --- a/servers/rendering/renderer_rd/shader_rd.h +++ b/servers/rendering/renderer_rd/shader_rd.h @@ -40,7 +40,15 @@ #include "core/variant/variant.h" #include "servers/rendering_server.h" +namespace RendererRD { + +class MaterialStorage; + +} + class ShaderRD { + friend class RendererRD::MaterialStorage; + public: struct VariantDefine { int group = 0; diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/SCsub b/servers/rendering/renderer_rd/shaders/forward_clustered/SCsub index f06a2d86e240..7337c2d026ed 100644 --- a/servers/rendering/renderer_rd/shaders/forward_clustered/SCsub +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/SCsub @@ -4,13 +4,18 @@ Import("env") if "RD_GLSL" in env["BUILDERS"]: # find all include files - gl_include_files = [str(f) for f in Glob("*_inc.glsl")] + [str(f) for f in Glob("../*_inc.glsl")] + gl_include_files = [str(f) for f in Glob("*_inc.glsl")] + gl_parent_include_files = [str(f) for f in Glob("../*_inc.glsl")] - # find all shader code(all glsl files excluding our include files) + # find all shader code (all glsl files excluding our include files) glsl_files = [str(f) for f in Glob("*.glsl") if str(f) not in gl_include_files] # make sure we recompile shaders if include files change - env.Depends([f + ".gen.h" for f in glsl_files], gl_include_files + ["#glsl_builders.py"]) + env.Depends([f + ".gen.h" for f in glsl_files], gl_include_files + gl_parent_include_files + ["#glsl_builders.py"]) + + # compile include files + for glsl_file in gl_include_files: + env.GLSL_HEADER(glsl_file) # compile shaders for glsl_file in glsl_files: diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl index cfde97af95f1..879f184434f7 100644 --- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl @@ -4,86 +4,12 @@ #VERSION_DEFINES -#include "scene_forward_clustered_inc.glsl" +#include "scene_forward_clustered_standard_inc.glsl" #define SHADER_IS_SRGB false #define SHADER_SPACE_FAR 0.0 -/* INPUT ATTRIBS */ - -// Always contains vertex position in XYZ, can contain tangent angle in W. -layout(location = 0) in vec4 vertex_angle_attrib; - -//only for pure render depth when normal is not used - -#if defined(NORMAL_USED) || defined(TANGENT_USED) -// Contains Normal/Axis in RG, can contain tangent in BA. -layout(location = 1) in vec4 axis_tangent_attrib; -#endif - -// Location 2 is unused. - -#if defined(COLOR_USED) -layout(location = 3) in vec4 color_attrib; -#endif - -#ifdef UV_USED -layout(location = 4) in vec2 uv_attrib; -#endif - -#if defined(UV2_USED) || defined(USE_LIGHTMAP) || defined(MODE_RENDER_MATERIAL) -layout(location = 5) in vec2 uv2_attrib; -#endif - -#if defined(CUSTOM0_USED) -layout(location = 6) in vec4 custom0_attrib; -#endif - -#if defined(CUSTOM1_USED) -layout(location = 7) in vec4 custom1_attrib; -#endif - -#if defined(CUSTOM2_USED) -layout(location = 8) in vec4 custom2_attrib; -#endif - -#if defined(CUSTOM3_USED) -layout(location = 9) in vec4 custom3_attrib; -#endif - -#if defined(BONES_USED) || defined(USE_PARTICLE_TRAILS) -layout(location = 10) in uvec4 bone_attrib; -#endif - -#if defined(WEIGHTS_USED) || defined(USE_PARTICLE_TRAILS) -layout(location = 11) in vec4 weight_attrib; -#endif - -#ifdef MOTION_VECTORS -layout(location = 12) in vec4 previous_vertex_attrib; - -#if defined(NORMAL_USED) || defined(TANGENT_USED) -layout(location = 13) in vec4 previous_normal_attrib; -#endif - -#endif // MOTION_VECTORS - -vec3 oct_to_vec3(vec2 e) { - vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y)); - float t = max(-v.z, 0.0); - v.xy += t * -sign(v.xy); - return normalize(v); -} - -void axis_angle_to_tbn(vec3 axis, float angle, out vec3 tangent, out vec3 binormal, out vec3 normal) { - float c = cos(angle); - float s = sin(angle); - vec3 omc_axis = (1.0 - c) * axis; - vec3 s_axis = s * axis; - tangent = omc_axis.xxx * axis + vec3(c, -s_axis.z, s_axis.y); - binormal = omc_axis.yyy * axis + vec3(s_axis.z, c, -s_axis.x); - normal = omc_axis.zzz * axis + vec3(-s_axis.y, s_axis.x, c); -} +#include "scene_forward_clustered_input_attributes_inc.glsl" /* Varyings */ @@ -115,12 +41,6 @@ layout(location = 7) out vec4 screen_position; layout(location = 8) out vec4 prev_screen_position; #endif -#ifdef MATERIAL_UNIFORMS_USED -layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms{ -#MATERIAL_UNIFORMS -} material; -#endif - float global_time; #ifdef MODE_DUAL_PARABOLOID @@ -132,28 +52,7 @@ layout(location = 9) out float dp_clip; layout(location = 10) out flat uint instance_index_interp; #ifdef USE_MULTIVIEW -#ifdef has_VK_KHR_multiview -#define ViewIndex gl_ViewIndex -#else // has_VK_KHR_multiview -// !BAS! This needs to become an input once we implement our fallback! -#define ViewIndex 0 -#endif // has_VK_KHR_multiview -vec3 multiview_uv(vec2 uv) { - return vec3(uv, ViewIndex); -} -ivec3 multiview_uv(ivec2 uv) { - return ivec3(uv, int(ViewIndex)); -} layout(location = 11) out vec4 combined_projected; -#else // USE_MULTIVIEW -// Set to zero, not supported in non stereo -#define ViewIndex 0 -vec2 multiview_uv(vec2 uv) { - return uv; -} -ivec2 multiview_uv(ivec2 uv) { - return uv; -} #endif //USE_MULTIVIEW invariant gl_Position; @@ -503,46 +402,6 @@ void vertex_shader(vec3 vertex_input, #endif } -void _unpack_vertex_attributes(vec4 p_vertex_in, vec3 p_compressed_aabb_position, vec3 p_compressed_aabb_size, -#if defined(NORMAL_USED) || defined(TANGENT_USED) - vec4 p_normal_in, -#ifdef NORMAL_USED - out vec3 r_normal, -#endif - out vec3 r_tangent, - out vec3 r_binormal, -#endif - out vec3 r_vertex) { - - r_vertex = p_vertex_in.xyz * p_compressed_aabb_size + p_compressed_aabb_position; -#ifdef NORMAL_USED - r_normal = oct_to_vec3(p_normal_in.xy * 2.0 - 1.0); -#endif - -#if defined(NORMAL_USED) || defined(TANGENT_USED) - - float binormal_sign; - - // This works because the oct value (0, 1) maps onto (0, 0, -1) which encodes to (1, 1). - // Accordingly, if p_normal_in.z contains octahedral values, it won't equal (0, 1). - if (p_normal_in.z > 0.0 || p_normal_in.w < 1.0) { - // Uncompressed format. - vec2 signed_tangent_attrib = p_normal_in.zw * 2.0 - 1.0; - r_tangent = oct_to_vec3(vec2(signed_tangent_attrib.x, abs(signed_tangent_attrib.y) * 2.0 - 1.0)); - binormal_sign = sign(signed_tangent_attrib.y); - r_binormal = normalize(cross(r_normal, r_tangent) * binormal_sign); - } else { - // Compressed format. - float angle = p_vertex_in.w; - binormal_sign = angle > 0.5 ? 1.0 : -1.0; // 0.5 does not exist in UNORM16, so values are either greater or smaller. - angle = abs(angle * 2.0 - 1.0) * M_PI; // 0.5 is basically zero, allowing to encode both signs reliably. - vec3 axis = r_normal; - axis_angle_to_tbn(axis, angle, r_tangent, r_binormal, r_normal); - r_binormal *= binormal_sign; - } -#endif -} - void main() { uint instance_index = draw_call.instance_index; @@ -591,10 +450,10 @@ void main() { prev_binormal, #endif instance_index, is_multimesh, draw_call.multimesh_motion_vectors_previous_offset, scene_data_block.prev_data, instances.data[instance_index].prev_transform, prev_screen_position); -#else +#else // MOTION_VECTORS // Unused output. vec4 screen_position; -#endif +#endif // MOTION_VECTORS vec3 vertex; #ifdef NORMAL_USED @@ -613,7 +472,7 @@ void main() { axis_tangent_attrib, #ifdef NORMAL_USED normal, -#endif +#endif // NORMAL_USED tangent, binormal, #endif @@ -641,30 +500,11 @@ void main() { #define SHADER_IS_SRGB false #define SHADER_SPACE_FAR 0.0 -/* Specialization Constants (Toggles) */ - -layout(constant_id = 0) const bool sc_use_forward_gi = false; -layout(constant_id = 1) const bool sc_use_light_projector = false; -layout(constant_id = 2) const bool sc_use_light_soft_shadows = false; -layout(constant_id = 3) const bool sc_use_directional_soft_shadows = false; - -/* Specialization Constants (Values) */ - -layout(constant_id = 6) const uint sc_soft_shadow_samples = 4; -layout(constant_id = 7) const uint sc_penumbra_shadow_samples = 4; - -layout(constant_id = 8) const uint sc_directional_soft_shadow_samples = 4; -layout(constant_id = 9) const uint sc_directional_penumbra_shadow_samples = 4; - -layout(constant_id = 10) const bool sc_decal_use_mipmaps = true; -layout(constant_id = 11) const bool sc_projector_use_mipmaps = true; -layout(constant_id = 12) const bool sc_use_depth_fog = false; -layout(constant_id = 13) const bool sc_use_lightmap_bicubic_filter = false; - // not used in clustered renderer but we share some code with the mobile renderer that requires this. const float sc_luminance_multiplier = 1.0; -#include "scene_forward_clustered_inc.glsl" +#include "scene_forward_clustered_specialization_constants_inc.glsl" +#include "scene_forward_clustered_standard_inc.glsl" /* Varyings */ @@ -766,28 +606,7 @@ vec4 textureArray_bicubic(texture2DArray tex, vec3 uv, vec2 texture_size) { #endif //USE_LIGHTMAP #ifdef USE_MULTIVIEW -#ifdef has_VK_KHR_multiview -#define ViewIndex gl_ViewIndex -#else // has_VK_KHR_multiview -// !BAS! This needs to become an input once we implement our fallback! -#define ViewIndex 0 -#endif // has_VK_KHR_multiview -vec3 multiview_uv(vec2 uv) { - return vec3(uv, ViewIndex); -} -ivec3 multiview_uv(ivec2 uv) { - return ivec3(uv, int(ViewIndex)); -} layout(location = 11) in vec4 combined_projected; -#else // USE_MULTIVIEW -// Set to zero, not supported in non stereo -#define ViewIndex 0 -vec2 multiview_uv(vec2 uv) { - return uv; -} -ivec2 multiview_uv(ivec2 uv) { - return uv; -} #endif //USE_MULTIVIEW //defines to keep compatibility with vertex @@ -807,52 +626,9 @@ ivec2 multiview_uv(ivec2 uv) { #define LIGHT_TRANSMITTANCE_USED #endif -#ifdef MATERIAL_UNIFORMS_USED -layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms{ - -#MATERIAL_UNIFORMS - -} material; -#endif - #GLOBALS -#ifdef MODE_RENDER_DEPTH - -#ifdef MODE_RENDER_MATERIAL - -layout(location = 0) out vec4 albedo_output_buffer; -layout(location = 1) out vec4 normal_output_buffer; -layout(location = 2) out vec4 orm_output_buffer; -layout(location = 3) out vec4 emission_output_buffer; -layout(location = 4) out float depth_output_buffer; - -#endif // MODE_RENDER_MATERIAL - -#ifdef MODE_RENDER_NORMAL_ROUGHNESS -layout(location = 0) out vec4 normal_roughness_output_buffer; - -#ifdef MODE_RENDER_VOXEL_GI -layout(location = 1) out uvec2 voxel_gi_buffer; -#endif - -#endif //MODE_RENDER_NORMAL -#else // RENDER DEPTH - -#ifdef MODE_SEPARATE_SPECULAR - -layout(location = 0) out vec4 diffuse_buffer; //diffuse (rgb) and roughness -layout(location = 1) out vec4 specular_buffer; //specular and SSS (subsurface scatter) -#else - -layout(location = 0) out vec4 frag_color; -#endif // MODE_SEPARATE_SPECULAR - -#endif // RENDER DEPTH - -#ifdef MOTION_VECTORS -layout(location = 2) out vec2 motion_vector; -#endif +#include "scene_forward_clustered_output_buffers_inc.glsl" #include "../scene_forward_aa_inc.glsl" diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_input_attributes_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_input_attributes_inc.glsl new file mode 100644 index 000000000000..137809c61aff --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_input_attributes_inc.glsl @@ -0,0 +1,115 @@ +/* INPUT ATTRIBS */ + +// Always contains vertex position in XYZ, can contain tangent angle in W. +layout(location = 0) in vec4 vertex_angle_attrib; + +//only for pure render depth when normal is not used + +#if defined(NORMAL_USED) || defined(TANGENT_USED) +// Contains Normal/Axis in RG, can contain tangent in BA. +layout(location = 1) in vec4 axis_tangent_attrib; +#endif + +// Location 2 is unused. + +#if defined(COLOR_USED) +layout(location = 3) in vec4 color_attrib; +#endif + +#ifdef UV_USED +layout(location = 4) in vec2 uv_attrib; +#endif + +#if defined(UV2_USED) || defined(USE_LIGHTMAP) || defined(MODE_RENDER_MATERIAL) +layout(location = 5) in vec2 uv2_attrib; +#endif + +#if defined(CUSTOM0_USED) +layout(location = 6) in vec4 custom0_attrib; +#endif + +#if defined(CUSTOM1_USED) +layout(location = 7) in vec4 custom1_attrib; +#endif + +#if defined(CUSTOM2_USED) +layout(location = 8) in vec4 custom2_attrib; +#endif + +#if defined(CUSTOM3_USED) +layout(location = 9) in vec4 custom3_attrib; +#endif + +#if defined(BONES_USED) || defined(USE_PARTICLE_TRAILS) +layout(location = 10) in uvec4 bone_attrib; +#endif + +#if defined(WEIGHTS_USED) || defined(USE_PARTICLE_TRAILS) +layout(location = 11) in vec4 weight_attrib; +#endif + +#ifdef MOTION_VECTORS +layout(location = 12) in vec4 previous_vertex_attrib; + +#if defined(NORMAL_USED) || defined(TANGENT_USED) +layout(location = 13) in vec4 previous_normal_attrib; +#endif + +#endif // MOTION_VECTORS + +vec3 oct_to_vec3(vec2 e) { + vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y)); + float t = max(-v.z, 0.0); + v.xy += t * -sign(v.xy); + return normalize(v); +} + +void axis_angle_to_tbn(vec3 axis, float angle, out vec3 tangent, out vec3 binormal, out vec3 normal) { + float c = cos(angle); + float s = sin(angle); + vec3 omc_axis = (1.0 - c) * axis; + vec3 s_axis = s * axis; + tangent = omc_axis.xxx * axis + vec3(c, -s_axis.z, s_axis.y); + binormal = omc_axis.yyy * axis + vec3(s_axis.z, c, -s_axis.x); + normal = omc_axis.zzz * axis + vec3(-s_axis.y, s_axis.x, c); +} + +void _unpack_vertex_attributes(vec4 p_vertex_in, vec3 p_compressed_aabb_position, vec3 p_compressed_aabb_size, +#if defined(NORMAL_USED) || defined(TANGENT_USED) + vec4 p_normal_in, +#ifdef NORMAL_USED + out vec3 r_normal, +#endif + out vec3 r_tangent, + out vec3 r_binormal, +#endif + out vec3 r_vertex) { + + r_vertex = p_vertex_in.xyz * p_compressed_aabb_size + p_compressed_aabb_position; +#ifdef NORMAL_USED + r_normal = oct_to_vec3(p_normal_in.xy * 2.0 - 1.0); +#endif + +#if defined(NORMAL_USED) || defined(TANGENT_USED) + + float binormal_sign; + + // This works because the oct value (0, 1) maps onto (0, 0, -1) which encodes to (1, 1). + // Accordingly, if p_normal_in.z contains octahedral values, it won't equal (0, 1). + if (p_normal_in.z > 0.0 || p_normal_in.w < 1.0) { + // Uncompressed format. + vec2 signed_tangent_attrib = p_normal_in.zw * 2.0 - 1.0; + r_tangent = oct_to_vec3(vec2(signed_tangent_attrib.x, abs(signed_tangent_attrib.y) * 2.0 - 1.0)); + binormal_sign = sign(signed_tangent_attrib.y); + r_binormal = normalize(cross(r_normal, r_tangent) * binormal_sign); + } else { + // Compressed format. + float angle = p_vertex_in.w; + binormal_sign = angle > 0.5 ? 1.0 : -1.0; // 0.5 does not exist in UNORM16, so values are either greater or smaller. + angle = abs(angle * 2.0 - 1.0) * M_PI; // 0.5 is basically zero, allowing to encode both signs reliably. + vec3 axis = r_normal; + axis_angle_to_tbn(axis, angle, r_tangent, r_binormal, r_normal); + r_binormal *= binormal_sign; + } +#endif +} diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_output_buffers_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_output_buffers_inc.glsl new file mode 100644 index 000000000000..6dee73100b58 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_output_buffers_inc.glsl @@ -0,0 +1,36 @@ +#ifdef MODE_RENDER_DEPTH + +#ifdef MODE_RENDER_MATERIAL + +layout(location = 0) out vec4 albedo_output_buffer; +layout(location = 1) out vec4 normal_output_buffer; +layout(location = 2) out vec4 orm_output_buffer; +layout(location = 3) out vec4 emission_output_buffer; +layout(location = 4) out float depth_output_buffer; + +#endif // MODE_RENDER_MATERIAL + +#ifdef MODE_RENDER_NORMAL_ROUGHNESS +layout(location = 0) out vec4 normal_roughness_output_buffer; + +#ifdef MODE_RENDER_VOXEL_GI +layout(location = 1) out uvec2 voxel_gi_buffer; +#endif + +#endif //MODE_RENDER_NORMAL +#else // RENDER DEPTH + +#ifdef MODE_SEPARATE_SPECULAR + +layout(location = 0) out vec4 diffuse_buffer; //diffuse (rgb) and roughness +layout(location = 1) out vec4 specular_buffer; //specular and SSS (subsurface scatter) +#else + +layout(location = 0) out vec4 frag_color; +#endif // MODE_SEPARATE_SPECULAR + +#endif // RENDER DEPTH + +#ifdef MOTION_VECTORS +layout(location = 2) out vec2 motion_vector; +#endif diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_specialization_constants_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_specialization_constants_inc.glsl new file mode 100644 index 000000000000..179fb240545c --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_specialization_constants_inc.glsl @@ -0,0 +1,19 @@ +/* Specialization Constants (Toggles) */ + +layout(constant_id = 0) const bool sc_use_forward_gi = false; +layout(constant_id = 1) const bool sc_use_light_projector = false; +layout(constant_id = 2) const bool sc_use_light_soft_shadows = false; +layout(constant_id = 3) const bool sc_use_directional_soft_shadows = false; + +/* Specialization Constants (Values) */ + +layout(constant_id = 6) const uint sc_soft_shadow_samples = 4; +layout(constant_id = 7) const uint sc_penumbra_shadow_samples = 4; + +layout(constant_id = 8) const uint sc_directional_soft_shadow_samples = 4; +layout(constant_id = 9) const uint sc_directional_penumbra_shadow_samples = 4; + +layout(constant_id = 10) const bool sc_decal_use_mipmaps = true; +layout(constant_id = 11) const bool sc_projector_use_mipmaps = true; +layout(constant_id = 12) const bool sc_use_depth_fog = false; +layout(constant_id = 13) const bool sc_use_lightmap_bicubic_filter = false; diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_standard_inc.glsl similarity index 92% rename from servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl rename to servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_standard_inc.glsl index 03511aa3a8c8..cfdfaa92953e 100644 --- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_standard_inc.glsl @@ -14,9 +14,30 @@ #endif #endif // MOLTENVK_USED -#if defined(USE_MULTIVIEW) && defined(has_VK_KHR_multiview) -#extension GL_EXT_multiview : enable -#endif +#ifdef USE_MULTIVIEW +#ifdef has_VK_KHR_multiview +#extension GL_EXT_multiview : enable // Enable our multiview GLSL extension +#define ViewIndex gl_ViewIndex +#else // has_VK_KHR_multiview +// This needs to become an input if we implement a fallback! +#define ViewIndex 0 +#endif // has_VK_KHR_multiview +vec3 multiview_uv(vec2 uv) { + return vec3(uv, ViewIndex); +} +ivec3 multiview_uv(ivec2 uv) { + return ivec3(uv, int(ViewIndex)); +} +#else // USE_MULTIVIEW +// Set to zero, not supported in non stereo +#define ViewIndex 0 +vec2 multiview_uv(vec2 uv) { + return uv; +} +ivec2 multiview_uv(ivec2 uv) { + return uv; +} +#endif //USE_MULTIVIEW #include "../cluster_data_inc.glsl" #include "../decal_data_inc.glsl" @@ -32,6 +53,8 @@ #define TANGENT_USED #endif +// Push constant + layout(push_constant, std430) uniform DrawCall { uint instance_index; uint uv_offset; @@ -349,3 +372,9 @@ layout(set = 2, binding = 0, std430) restrict readonly buffer Transforms { transforms; /* Set 3 User Material */ + +#ifdef MATERIAL_UNIFORMS_USED +layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms{ +#MATERIAL_UNIFORMS +} material; +#endif diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/SCsub b/servers/rendering/renderer_rd/shaders/forward_mobile/SCsub index f06a2d86e240..898b838151c2 100644 --- a/servers/rendering/renderer_rd/shaders/forward_mobile/SCsub +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/SCsub @@ -4,13 +4,18 @@ Import("env") if "RD_GLSL" in env["BUILDERS"]: # find all include files - gl_include_files = [str(f) for f in Glob("*_inc.glsl")] + [str(f) for f in Glob("../*_inc.glsl")] + gl_include_files = [str(f) for f in Glob("*_inc.glsl")] + gl_parent_include_files = [str(f) for f in Glob("../*_inc.glsl")] # find all shader code(all glsl files excluding our include files) glsl_files = [str(f) for f in Glob("*.glsl") if str(f) not in gl_include_files] # make sure we recompile shaders if include files change - env.Depends([f + ".gen.h" for f in glsl_files], gl_include_files + ["#glsl_builders.py"]) + env.Depends([f + ".gen.h" for f in glsl_files], gl_include_files + gl_parent_include_files + ["#glsl_builders.py"]) + + # compile include files + for glsl_file in gl_include_files: + env.GLSL_HEADER(glsl_file) # compile shaders for glsl_file in glsl_files: diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl index b21769f20747..e48b5ba172f7 100644 --- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl @@ -5,81 +5,13 @@ #VERSION_DEFINES /* Include our forward mobile UBOs definitions etc. */ -#include "scene_forward_mobile_inc.glsl" +#include "scene_forward_mobile_standard_inc.glsl" #define SHADER_IS_SRGB false #define SHADER_SPACE_FAR 0.0 -/* INPUT ATTRIBS */ - -// Always contains vertex position in XYZ, can contain tangent angle in W. -layout(location = 0) in vec4 vertex_angle_attrib; - -//only for pure render depth when normal is not used - -#ifdef NORMAL_USED -// Contains Normal/Axis in RG, can contain tangent in BA. -layout(location = 1) in vec4 axis_tangent_attrib; -#endif - -// Location 2 is unused. - -#if defined(COLOR_USED) -layout(location = 3) in vec4 color_attrib; -#endif - -#ifdef UV_USED -layout(location = 4) in vec2 uv_attrib; -#endif - -#if defined(UV2_USED) || defined(USE_LIGHTMAP) || defined(MODE_RENDER_MATERIAL) -layout(location = 5) in vec2 uv2_attrib; -#endif // MODE_RENDER_MATERIAL - -#if defined(CUSTOM0_USED) -layout(location = 6) in vec4 custom0_attrib; -#endif - -#if defined(CUSTOM1_USED) -layout(location = 7) in vec4 custom1_attrib; -#endif - -#if defined(CUSTOM2_USED) -layout(location = 8) in vec4 custom2_attrib; -#endif - -#if defined(CUSTOM3_USED) -layout(location = 9) in vec4 custom3_attrib; -#endif - -#if defined(BONES_USED) || defined(USE_PARTICLE_TRAILS) -layout(location = 10) in uvec4 bone_attrib; -#endif - -#if defined(WEIGHTS_USED) || defined(USE_PARTICLE_TRAILS) -layout(location = 11) in vec4 weight_attrib; -#endif - -vec3 oct_to_vec3(vec2 e) { - vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y)); - float t = max(-v.z, 0.0); - v.xy += t * -sign(v.xy); - return normalize(v); -} - -void axis_angle_to_tbn(vec3 axis, float angle, out vec3 tangent, out vec3 binormal, out vec3 normal) { - float c = cos(angle); - float s = sin(angle); - vec3 omc_axis = (1.0 - c) * axis; - vec3 s_axis = s * axis; - tangent = omc_axis.xxx * axis + vec3(c, -s_axis.z, s_axis.y); - binormal = omc_axis.yyy * axis + vec3(s_axis.z, c, -s_axis.x); - normal = omc_axis.zzz * axis + vec3(-s_axis.y, s_axis.x, c); -} - -/* Spec Constants */ - -layout(constant_id = 17) const bool sc_is_multimesh = false; +#include "scene_forward_mobile_input_attributes_inc.glsl" +#include "scene_forward_mobile_specialization_constants_inc.glsl" /* Varyings */ @@ -106,44 +38,12 @@ layout(location = 5) mediump out vec3 tangent_interp; layout(location = 6) mediump out vec3 binormal_interp; #endif -#ifdef MATERIAL_UNIFORMS_USED -layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms{ - -#MATERIAL_UNIFORMS - -} material; -#endif - #ifdef MODE_DUAL_PARABOLOID layout(location = 9) out highp float dp_clip; #endif -#ifdef USE_MULTIVIEW -#ifdef has_VK_KHR_multiview -#define ViewIndex gl_ViewIndex -#else -// !BAS! This needs to become an input once we implement our fallback! -#define ViewIndex 0 -#endif -vec3 multiview_uv(vec2 uv) { - return vec3(uv, ViewIndex); -} -ivec3 multiview_uv(ivec2 uv) { - return ivec3(uv, int(ViewIndex)); -} -#else -// Set to zero, not supported in non stereo -#define ViewIndex 0 -vec2 multiview_uv(vec2 uv) { - return uv; -} -ivec2 multiview_uv(ivec2 uv) { - return uv; -} -#endif //USE_MULTIVIEW - invariant gl_Position; #GLOBALS @@ -306,33 +206,30 @@ void main() { model_normal_matrix = model_normal_matrix * mat3(matrix); } - vec3 vertex = vertex_angle_attrib.xyz * instances.data[draw_call.instance_index].compressed_aabb_size_pad.xyz + instances.data[draw_call.instance_index].compressed_aabb_position_pad.xyz; + vec3 vertex; #ifdef NORMAL_USED - vec3 normal = oct_to_vec3(axis_tangent_attrib.xy * 2.0 - 1.0); + vec3 normal; #endif - #if defined(NORMAL_USED) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) - vec3 binormal; float binormal_sign; vec3 tangent; - if (axis_tangent_attrib.z > 0.0 || axis_tangent_attrib.w < 1.0) { - // Uncompressed format. - vec2 signed_tangent_attrib = axis_tangent_attrib.zw * 2.0 - 1.0; - tangent = oct_to_vec3(vec2(signed_tangent_attrib.x, abs(signed_tangent_attrib.y) * 2.0 - 1.0)); - binormal_sign = sign(signed_tangent_attrib.y); - binormal = normalize(cross(normal, tangent) * binormal_sign); - } else { - // Compressed format. - float angle = vertex_angle_attrib.w; - binormal_sign = angle > 0.5 ? 1.0 : -1.0; // 0.5 does not exist in UNORM16, so values are either greater or smaller. - angle = abs(angle * 2.0 - 1.0) * M_PI; // 0.5 is basically zero, allowing to encode both signs reliably. - vec3 axis = normal; - axis_angle_to_tbn(axis, angle, tangent, binormal, normal); - binormal *= binormal_sign; - } #endif + _unpack_vertex_attributes( + vertex_angle_attrib, + instances.data[draw_call.instance_index].compressed_aabb_position_pad.xyz, + instances.data[draw_call.instance_index].compressed_aabb_size_pad.xyz, +#if defined(NORMAL_USED) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) + axis_tangent_attrib, +#ifdef NORMAL_USED + normal, +#endif // NORMAL_USED + tangent, + binormal, +#endif + vertex); + #ifdef UV_USED uv_interp = uv_attrib; #endif @@ -503,41 +400,10 @@ void main() { /* Specialization Constants */ -#if !defined(MODE_RENDER_DEPTH) - -#if !defined(MODE_UNSHADED) - -layout(constant_id = 0) const bool sc_use_light_projector = false; -layout(constant_id = 1) const bool sc_use_light_soft_shadows = false; -layout(constant_id = 2) const bool sc_use_directional_soft_shadows = false; - -layout(constant_id = 3) const uint sc_soft_shadow_samples = 4; -layout(constant_id = 4) const uint sc_penumbra_shadow_samples = 4; - -layout(constant_id = 5) const uint sc_directional_soft_shadow_samples = 4; -layout(constant_id = 6) const uint sc_directional_penumbra_shadow_samples = 4; - -layout(constant_id = 8) const bool sc_projector_use_mipmaps = true; - -layout(constant_id = 9) const bool sc_disable_omni_lights = false; -layout(constant_id = 10) const bool sc_disable_spot_lights = false; -layout(constant_id = 11) const bool sc_disable_reflection_probes = false; -layout(constant_id = 12) const bool sc_disable_directional_lights = false; -layout(constant_id = 18) const bool sc_use_lightmap_bicubic_filter = false; - -#endif //!MODE_UNSHADED - -layout(constant_id = 7) const bool sc_decal_use_mipmaps = true; -layout(constant_id = 13) const bool sc_disable_decals = false; -layout(constant_id = 14) const bool sc_disable_fog = false; -layout(constant_id = 16) const bool sc_use_depth_fog = false; - -#endif //!MODE_RENDER_DEPTH - -layout(constant_id = 15) const float sc_luminance_multiplier = 2.0; +#include "scene_forward_mobile_specialization_constants_inc.glsl" /* Include our forward mobile UBOs definitions etc. */ -#include "scene_forward_mobile_inc.glsl" +#include "scene_forward_mobile_standard_inc.glsl" /* Varyings */ @@ -631,30 +497,6 @@ vec4 textureArray_bicubic(texture2DArray tex, vec3 uv, vec2 texture_size) { } #endif //USE_LIGHTMAP -#ifdef USE_MULTIVIEW -#ifdef has_VK_KHR_multiview -#define ViewIndex gl_ViewIndex -#else -// !BAS! This needs to become an input once we implement our fallback! -#define ViewIndex 0 -#endif -vec3 multiview_uv(vec2 uv) { - return vec3(uv, ViewIndex); -} -ivec3 multiview_uv(ivec2 uv) { - return ivec3(uv, int(ViewIndex)); -} -#else -// Set to zero, not supported in non stereo -#define ViewIndex 0 -vec2 multiview_uv(vec2 uv) { - return uv; -} -ivec2 multiview_uv(ivec2 uv) { - return uv; -} -#endif //USE_MULTIVIEW - //defines to keep compatibility with vertex #ifdef USE_MULTIVIEW @@ -670,42 +512,11 @@ ivec2 multiview_uv(ivec2 uv) { #define LIGHT_TRANSMITTANCE_USED #endif -#ifdef MATERIAL_UNIFORMS_USED -layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms{ - -#MATERIAL_UNIFORMS - -} material; -#endif - #GLOBALS -/* clang-format on */ - -#ifdef MODE_RENDER_DEPTH - -#ifdef MODE_RENDER_MATERIAL - -layout(location = 0) out vec4 albedo_output_buffer; -layout(location = 1) out vec4 normal_output_buffer; -layout(location = 2) out vec4 orm_output_buffer; -layout(location = 3) out vec4 emission_output_buffer; -layout(location = 4) out float depth_output_buffer; - -#endif // MODE_RENDER_MATERIAL - -#else // RENDER DEPTH +#include "scene_forward_mobile_output_buffers_inc.glsl" -#ifdef MODE_MULTIPLE_RENDER_TARGETS - -layout(location = 0) out vec4 diffuse_buffer; //diffuse (rgb) and roughness -layout(location = 1) out vec4 specular_buffer; //specular and SSS (subsurface scatter) -#else - -layout(location = 0) out mediump vec4 frag_color; -#endif // MODE_MULTIPLE_RENDER_TARGETS - -#endif // RENDER DEPTH +/* clang-format on */ #include "../scene_forward_aa_inc.glsl" diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_input_attributes_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_input_attributes_inc.glsl new file mode 100644 index 000000000000..9cb6957c87e7 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_input_attributes_inc.glsl @@ -0,0 +1,106 @@ +/* INPUT ATTRIBS */ + +// Always contains vertex position in XYZ, can contain tangent angle in W. +layout(location = 0) in vec4 vertex_angle_attrib; + +//only for pure render depth when normal is not used + +#ifdef NORMAL_USED +// Contains Normal/Axis in RG, can contain tangent in BA. +layout(location = 1) in vec4 axis_tangent_attrib; +#endif + +// Location 2 is unused. + +#if defined(COLOR_USED) +layout(location = 3) in vec4 color_attrib; +#endif + +#ifdef UV_USED +layout(location = 4) in vec2 uv_attrib; +#endif + +#if defined(UV2_USED) || defined(USE_LIGHTMAP) || defined(MODE_RENDER_MATERIAL) +layout(location = 5) in vec2 uv2_attrib; +#endif // MODE_RENDER_MATERIAL + +#if defined(CUSTOM0_USED) +layout(location = 6) in vec4 custom0_attrib; +#endif + +#if defined(CUSTOM1_USED) +layout(location = 7) in vec4 custom1_attrib; +#endif + +#if defined(CUSTOM2_USED) +layout(location = 8) in vec4 custom2_attrib; +#endif + +#if defined(CUSTOM3_USED) +layout(location = 9) in vec4 custom3_attrib; +#endif + +#if defined(BONES_USED) || defined(USE_PARTICLE_TRAILS) +layout(location = 10) in uvec4 bone_attrib; +#endif + +#if defined(WEIGHTS_USED) || defined(USE_PARTICLE_TRAILS) +layout(location = 11) in vec4 weight_attrib; +#endif + +vec3 oct_to_vec3(vec2 e) { + vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y)); + float t = max(-v.z, 0.0); + v.xy += t * -sign(v.xy); + return normalize(v); +} + +void axis_angle_to_tbn(vec3 axis, float angle, out vec3 tangent, out vec3 binormal, out vec3 normal) { + float c = cos(angle); + float s = sin(angle); + vec3 omc_axis = (1.0 - c) * axis; + vec3 s_axis = s * axis; + tangent = omc_axis.xxx * axis + vec3(c, -s_axis.z, s_axis.y); + binormal = omc_axis.yyy * axis + vec3(s_axis.z, c, -s_axis.x); + normal = omc_axis.zzz * axis + vec3(-s_axis.y, s_axis.x, c); +} + +void _unpack_vertex_attributes(vec4 p_vertex_in, vec3 p_compressed_aabb_position, vec3 p_compressed_aabb_size, +#if defined(NORMAL_USED) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) + vec4 p_normal_in, +#ifdef NORMAL_USED + out vec3 r_normal, +#endif + out vec3 r_tangent, + out vec3 r_binormal, +#endif + out vec3 r_vertex) { + + r_vertex = p_vertex_in.xyz * p_compressed_aabb_size + p_compressed_aabb_position; +#ifdef NORMAL_USED + r_normal = oct_to_vec3(p_normal_in.xy * 2.0 - 1.0); +#endif + +#if defined(NORMAL_USED) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) + + float binormal_sign; + + // This works because the oct value (0, 1) maps onto (0, 0, -1) which encodes to (1, 1). + // Accordingly, if p_normal_in.z contains octahedral values, it won't equal (0, 1). + if (p_normal_in.z > 0.0 || p_normal_in.w < 1.0) { + // Uncompressed format. + vec2 signed_tangent_attrib = p_normal_in.zw * 2.0 - 1.0; + r_tangent = oct_to_vec3(vec2(signed_tangent_attrib.x, abs(signed_tangent_attrib.y) * 2.0 - 1.0)); + binormal_sign = sign(signed_tangent_attrib.y); + r_binormal = normalize(cross(r_normal, r_tangent) * binormal_sign); + } else { + // Compressed format. + float angle = p_vertex_in.w; + binormal_sign = angle > 0.5 ? 1.0 : -1.0; // 0.5 does not exist in UNORM16, so values are either greater or smaller. + angle = abs(angle * 2.0 - 1.0) * M_PI; // 0.5 is basically zero, allowing to encode both signs reliably. + vec3 axis = r_normal; + axis_angle_to_tbn(axis, angle, r_tangent, r_binormal, r_normal); + r_binormal *= binormal_sign; + } +#endif +} diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_output_buffers_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_output_buffers_inc.glsl new file mode 100644 index 000000000000..f681ad5451f3 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_output_buffers_inc.glsl @@ -0,0 +1,24 @@ +#ifdef MODE_RENDER_DEPTH + +#ifdef MODE_RENDER_MATERIAL + +layout(location = 0) out vec4 albedo_output_buffer; +layout(location = 1) out vec4 normal_output_buffer; +layout(location = 2) out vec4 orm_output_buffer; +layout(location = 3) out vec4 emission_output_buffer; +layout(location = 4) out float depth_output_buffer; + +#endif // MODE_RENDER_MATERIAL + +#else // RENDER DEPTH + +#ifdef MODE_MULTIPLE_RENDER_TARGETS + +layout(location = 0) out vec4 diffuse_buffer; //diffuse (rgb) and roughness +layout(location = 1) out vec4 specular_buffer; //specular and SSS (subsurface scatter) +#else + +layout(location = 0) out mediump vec4 frag_color; +#endif // MODE_MULTIPLE_RENDER_TARGETS + +#endif // RENDER DEPTH diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_specialization_constants_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_specialization_constants_inc.glsl new file mode 100644 index 000000000000..4bfdce43e0f3 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_specialization_constants_inc.glsl @@ -0,0 +1,35 @@ +/* Spec Constants */ + +#if !defined(MODE_RENDER_DEPTH) + +#if !defined(MODE_UNSHADED) + +layout(constant_id = 0) const bool sc_use_light_projector = false; +layout(constant_id = 1) const bool sc_use_light_soft_shadows = false; +layout(constant_id = 2) const bool sc_use_directional_soft_shadows = false; + +layout(constant_id = 3) const uint sc_soft_shadow_samples = 4; +layout(constant_id = 4) const uint sc_penumbra_shadow_samples = 4; + +layout(constant_id = 5) const uint sc_directional_soft_shadow_samples = 4; +layout(constant_id = 6) const uint sc_directional_penumbra_shadow_samples = 4; + +layout(constant_id = 8) const bool sc_projector_use_mipmaps = true; + +layout(constant_id = 9) const bool sc_disable_omni_lights = false; +layout(constant_id = 10) const bool sc_disable_spot_lights = false; +layout(constant_id = 11) const bool sc_disable_reflection_probes = false; +layout(constant_id = 12) const bool sc_disable_directional_lights = false; +layout(constant_id = 18) const bool sc_use_lightmap_bicubic_filter = false; + +#endif //!MODE_UNSHADED + +layout(constant_id = 7) const bool sc_decal_use_mipmaps = true; +layout(constant_id = 13) const bool sc_disable_decals = false; +layout(constant_id = 14) const bool sc_disable_fog = false; +layout(constant_id = 16) const bool sc_use_depth_fog = false; + +#endif //!MODE_RENDER_DEPTH + +layout(constant_id = 15) const float sc_luminance_multiplier = 2.0; +layout(constant_id = 17) const bool sc_is_multimesh = false; diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_standard_inc.glsl similarity index 90% rename from servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl rename to servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_standard_inc.glsl index d971ff04c5eb..7840664aea38 100644 --- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_standard_inc.glsl @@ -1,9 +1,30 @@ #define M_PI 3.14159265359 #define MAX_VIEWS 2 -#if defined(USE_MULTIVIEW) && defined(has_VK_KHR_multiview) +#ifdef USE_MULTIVIEW +#ifdef has_VK_KHR_multiview #extension GL_EXT_multiview : enable +#define ViewIndex gl_ViewIndex +#else +// !BAS! This needs to become an input once we implement our fallback! +#define ViewIndex 0 #endif +vec3 multiview_uv(vec2 uv) { + return vec3(uv, ViewIndex); +} +ivec3 multiview_uv(ivec2 uv) { + return ivec3(uv, int(ViewIndex)); +} +#else +// Set to zero, not supported in non stereo +#define ViewIndex 0 +vec2 multiview_uv(vec2 uv) { + return uv; +} +ivec2 multiview_uv(ivec2 uv) { + return uv; +} +#endif //USE_MULTIVIEW #include "../decal_data_inc.glsl" #include "../scene_data_inc.glsl" @@ -16,6 +37,8 @@ #define USING_MOBILE_RENDERER +// Push constant + layout(push_constant, std430) uniform DrawCall { vec2 uv_offset; uint instance_index; @@ -190,3 +213,9 @@ layout(set = 2, binding = 0, std430) restrict readonly buffer Transforms { transforms; /* Set 3 User Material */ + +#ifdef MATERIAL_UNIFORMS_USED +layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms{ +#MATERIAL_UNIFORMS +} material; +#endif diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp index 63dc54e24cae..b078c96f1b3e 100644 --- a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp @@ -1184,7 +1184,10 @@ MaterialStorage::~MaterialStorage() { } bool MaterialStorage::free(RID p_rid) { - if (owns_shader(p_rid)) { + if (owns_shader_template(p_rid)) { + shader_template_free(p_rid); + return true; + } else if (owns_shader(p_rid)) { shader_free(p_rid); return true; } else if (owns_material(p_rid)) { @@ -1813,6 +1816,205 @@ void MaterialStorage::_update_global_shader_uniforms() { } } +/* SHADER TEMPLATE API */ + +void MaterialStorage::ShaderTemplate::cleanup() { + if (shader) { + memdelete(shader); + shader = nullptr; + } + initialized = false; +} + +RID MaterialStorage::shader_template_allocate() { + return shader_template_owner.allocate_rid(); +} + +void MaterialStorage::shader_template_initialize(RID p_rid) { + ShaderTemplate shader_template; + shader_template.self = p_rid; + + shader_template_owner.initialize_rid(p_rid, shader_template); +} + +void MaterialStorage::shader_template_free(RID p_rid) { + ShaderTemplate *shader_template = shader_template_owner.get_or_null(p_rid); + ERR_FAIL_NULL(shader_template); + + // Make sure our shaders are unreferenced. + while (shader_template->owners.size()) { + shader_set_shader_template((*shader_template->owners.begin())->self, RID()); + } + + shader_template->cleanup(); + shader_template_owner.free(p_rid); +} + +void MaterialStorage::shader_template_set_raster_code(RID p_template_shader, const String &p_vertex_code, const String &p_fragment_code, const String &p_name) { + HashMap org_code; + ShaderTemplate *shader_template = shader_template_owner.get_or_null(p_template_shader); + ERR_FAIL_NULL(shader_template); + + // Remember code for shaders that use this template and clear the shader data. + for (Shader *shader : shader_template->owners) { + if (shader->data) { + org_code[shader] = shader->code; // Make a copy, we're about to loose it. + + // Delete the old shader data. + memdelete(shader->data); + shader->data = nullptr; + shader->type = SHADER_TYPE_MAX; + } + } + + // Cleanup our shader template. + shader_template->cleanup(); + + // Create our new shader for this template. + shader_template->shader = memnew(ShaderRD); + if (shader_template->shader) { + shader_template->shader->setup(p_vertex_code.utf8().get_data(), p_fragment_code.utf8().get_data(), nullptr, p_name.utf8().get_data()); + } + + // And recompile the shaders if applicable. + for (Shader *shader : shader_template->owners) { + if (!org_code[shader].is_empty()) { + shader_set_code(shader->self, org_code[shader]); + } + } +} + +void MaterialStorage::shader_template_set_shader(RID p_template_shader, ShaderRD *p_shader) { + ShaderTemplate *shader_template = shader_template_owner.get_or_null(p_template_shader); + ERR_FAIL_NULL(shader_template); + + // Note: this should only be called for setting up our default shader template. + // No dependencies are managed for our default shader template. + + shader_template->cleanup(); + + shader_template->shader = p_shader; +} + +bool MaterialStorage::shader_template_is_initialized(RID p_template_shader) { + ShaderTemplate *shader_template = shader_template_owner.get_or_null(p_template_shader); + ERR_FAIL_NULL_V(shader_template, false); + + return shader_template->initialized; +} + +void MaterialStorage::shader_template_initialize(RID p_template_shader, const Vector &p_variant_defines, const String &p_general_defines) { + ShaderTemplate *shader_template = shader_template_owner.get_or_null(p_template_shader); + ERR_FAIL_NULL(shader_template); + ERR_FAIL_NULL(shader_template->shader); + ERR_FAIL_COND(shader_template->initialized); + + shader_template->shader->initialize(p_variant_defines, p_general_defines); + + shader_template->initialized = true; +} + +void MaterialStorage::shader_template_initialize(RID p_template_shader, const Vector &p_variant_defines, const String &p_general_defines) { + ShaderTemplate *shader_template = shader_template_owner.get_or_null(p_template_shader); + ERR_FAIL_NULL(shader_template); + ERR_FAIL_NULL(shader_template->shader); + ERR_FAIL_COND(shader_template->initialized); + + shader_template->shader->initialize(p_variant_defines, p_general_defines); + + shader_template->initialized = true; +} + +void MaterialStorage::shader_template_set_variant_enabled(RID p_template_shader, int p_variant, bool p_enabled) { + ShaderTemplate *shader_template = shader_template_owner.get_or_null(p_template_shader); + ERR_FAIL_NULL(shader_template); + ERR_FAIL_NULL(shader_template->shader); + ERR_FAIL_COND(!shader_template->initialized); + + shader_template->shader->set_variant_enabled(p_variant, p_enabled); +} + +bool MaterialStorage::shader_template_is_variant_enabled(RID p_template_shader, int p_variant) const { + ShaderTemplate *shader_template = shader_template_owner.get_or_null(p_template_shader); + ERR_FAIL_NULL_V(shader_template, false); + ERR_FAIL_NULL_V(shader_template->shader, false); + ERR_FAIL_COND_V(!shader_template->initialized, false); + + return shader_template->shader->is_variant_enabled(p_variant); +} + +void MaterialStorage::shader_template_enable_group(RID p_template_shader, int p_group) { + ShaderTemplate *shader_template = shader_template_owner.get_or_null(p_template_shader); + ERR_FAIL_NULL(shader_template); + ERR_FAIL_NULL(shader_template->shader); + ERR_FAIL_COND(!shader_template->initialized); + + shader_template->shader->enable_group(p_group); +} + +void MaterialStorage::shader_template_enable_group_on_all(int p_group) { + List owned; + shader_template_owner.get_owned_list(&owned); + + for (RID &rid : owned) { + shader_template_enable_group(rid, p_group); + } +} + +RID MaterialStorage::shader_template_version_create(RID p_template_shader) { + ShaderTemplate *shader_template = shader_template_owner.get_or_null(p_template_shader); + ERR_FAIL_NULL_V(shader_template, RID()); + ERR_FAIL_NULL_V(shader_template->shader, RID()); + ERR_FAIL_COND_V(!shader_template->initialized, RID()); + + return shader_template->shader->version_create(); +} + +void MaterialStorage::shader_template_version_free(RID p_template_shader, RID p_version) { + ShaderTemplate *shader_template = shader_template_owner.get_or_null(p_template_shader); + ERR_FAIL_NULL(shader_template); + ERR_FAIL_NULL(shader_template->shader); + ERR_FAIL_COND(!shader_template->initialized); + + shader_template->shader->version_free(p_version); +} + +void MaterialStorage::shader_template_version_set_code(RID p_template_shader, RID p_version, const HashMap &p_code, const String &p_uniforms, const String &p_vertex_globals, const String &p_fragment_globals, const Vector &p_custom_defines) { + ShaderTemplate *shader_template = shader_template_owner.get_or_null(p_template_shader); + ERR_FAIL_NULL(shader_template); + ERR_FAIL_NULL(shader_template->shader); + ERR_FAIL_COND(!shader_template->initialized); + + return shader_template->shader->version_set_code(p_version, p_code, p_uniforms, p_vertex_globals, p_fragment_globals, p_custom_defines); +} + +bool MaterialStorage::shader_template_version_is_valid(RID p_template_shader, RID p_version) { + ShaderTemplate *shader_template = shader_template_owner.get_or_null(p_template_shader); + ERR_FAIL_NULL_V(shader_template, false); + ERR_FAIL_NULL_V(shader_template->shader, false); + ERR_FAIL_COND_V(!shader_template->initialized, false); + + return shader_template->shader->version_is_valid(p_version); +} + +RID MaterialStorage::shader_template_version_get_shader(RID p_template_shader, RID p_version, int p_variant) { + ShaderTemplate *shader_template = shader_template_owner.get_or_null(p_template_shader); + ERR_FAIL_NULL_V(shader_template, RID()); + ERR_FAIL_NULL_V(shader_template->shader, RID()); + ERR_FAIL_COND_V(!shader_template->initialized, RID()); + + return shader_template->shader->version_get_shader(p_version, p_variant); +} + +RS::ShaderNativeSourceCode MaterialStorage::shader_template_version_get_native_source_code(RID p_template_shader, RID p_version) { + ShaderTemplate *shader_template = shader_template_owner.get_or_null(p_template_shader); + ERR_FAIL_NULL_V(shader_template, RS::ShaderNativeSourceCode()); + ERR_FAIL_NULL_V(shader_template->shader, RS::ShaderNativeSourceCode()); + ERR_FAIL_COND_V(!shader_template->initialized, RS::ShaderNativeSourceCode()); + + return shader_template->shader->version_get_native_source_code(p_version); +} + /* SHADER API */ RID MaterialStorage::shader_allocate() { @@ -1823,6 +2025,7 @@ void MaterialStorage::shader_initialize(RID p_rid) { Shader shader; shader.data = nullptr; shader.type = SHADER_TYPE_MAX; + shader.self = p_rid; shader_owner.initialize_rid(p_rid, shader); } @@ -1831,18 +2034,57 @@ void MaterialStorage::shader_free(RID p_rid) { Shader *shader = shader_owner.get_or_null(p_rid); ERR_FAIL_NULL(shader); - //make material unreference this + // Clear our shader template. + shader_set_shader_template(p_rid, RID(), true); + + // Make material unreference this. while (shader->owners.size()) { material_set_shader((*shader->owners.begin())->self, RID()); } - //clear data if exists + // Clear data if exists. if (shader->data) { memdelete(shader->data); } + shader_owner.free(p_rid); } +void MaterialStorage::shader_set_shader_template(RID p_shader, RID p_shader_template, bool p_clear_code) { + Shader *shader = shader_owner.get_or_null(p_shader); + ERR_FAIL_NULL(shader); + ShaderTemplate *shader_template = shader_template_owner.get_or_null(p_shader_template); + + if (shader->shader_template != shader_template) { + String org_code; + + if (shader->data) { + org_code = shader->code; // Make a copy, we're about to loose it. + memdelete(shader->data); + shader->type = SHADER_TYPE_MAX; + shader->data = nullptr; + } + + if (shader->shader_template) { + shader->shader_template->owners.erase(shader); + } + shader->shader_template = shader_template; + if (shader->shader_template) { + shader->shader_template->owners.insert(shader); + } + + // Trigger recompile, but only if we have shader data. + // This should prevent a double compile as long as we set our + // template before we set our code! + // TODO we do have a problem that if the shader template gets freed + // before our shaders get freed during closing, we trigger a recompile + // with the built-in shader. + if (!org_code.is_empty() && !p_clear_code) { + shader_set_code(p_shader, org_code); + } + } +} + void MaterialStorage::shader_set_code(RID p_shader, const String &p_code) { Shader *shader = shader_owner.get_or_null(p_shader); ERR_FAIL_NULL(shader); @@ -1909,8 +2151,13 @@ void MaterialStorage::shader_set_code(RID p_shader, const String &p_code) { } if (shader->data) { + RID shader_template; + if (shader->shader_template) { + shader_template = shader->shader_template->self; + } + shader->data->set_path_hint(shader->path_hint); - shader->data->set_code(p_code); + shader->data->set_code(p_code, shader_template); } for (Material *E : shader->owners) { diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.h b/servers/rendering/renderer_rd/storage_rd/material_storage.h index 9c53450462ef..66fb86901601 100644 --- a/servers/rendering/renderer_rd/storage_rd/material_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/material_storage.h @@ -37,6 +37,7 @@ #include "core/templates/local_vector.h" #include "core/templates/rid_owner.h" #include "core/templates/self_list.h" +#include "servers/rendering/renderer_rd/shader_rd.h" #include "servers/rendering/shader_compiler.h" #include "servers/rendering/shader_language.h" #include "servers/rendering/storage/material_storage.h" @@ -67,7 +68,7 @@ class MaterialStorage : public RendererMaterialStorage { virtual void get_instance_param_list(List *p_param_list) const; virtual bool is_parameter_texture(const StringName &p_param) const; - virtual void set_code(const String &p_Code) = 0; + virtual void set_code(const String &p_Code, RID p_shader_template = RID()) = 0; virtual bool is_animated() const = 0; virtual bool casts_shadows() const = 0; virtual RS::ShaderNativeSourceCode get_native_source_code() const { return RS::ShaderNativeSourceCode(); } @@ -196,12 +197,31 @@ class MaterialStorage : public RendererMaterialStorage { void _global_shader_uniform_store_in_buffer(int32_t p_index, RS::GlobalShaderParameterType p_type, const Variant &p_value); void _global_shader_uniform_mark_buffer_dirty(int32_t p_index, int32_t p_elements); + /* SHADER TEMPLATE API */ + + struct Shader; + + struct ShaderTemplate { + RID self; + ShaderRD *shader = nullptr; + bool initialized = false; + + HashSet owners; + + void cleanup(); + }; + + mutable RID_Owner shader_template_owner; + ShaderTemplate *get_shader_template(RID p_rid) { return shader_template_owner.get_or_null(p_rid); } + /* SHADER API */ struct Material; struct Shader { + RID self; ShaderData *data = nullptr; + ShaderTemplate *shader_template = nullptr; String code; String path_hint; ShaderType type; @@ -387,6 +407,34 @@ class MaterialStorage : public RendererMaterialStorage { RID global_shader_uniforms_get_storage_buffer() const; + /* SHADER TEMPLATE API */ + + bool owns_shader_template(RID p_rid) { return shader_template_owner.owns(p_rid); }; + + virtual RID shader_template_allocate() override; + virtual void shader_template_initialize(RID p_rid) override; + virtual void shader_template_free(RID p_rid) override; + + virtual void shader_template_set_raster_code(RID p_template_shader, const String &p_vertex_code, const String &p_fragment_code, const String &p_name) override; + void shader_template_set_shader(RID p_template_shader, ShaderRD *p_shader); // note, this takes ownership of the shader! + + // setup + bool shader_template_is_initialized(RID p_template_shader); + void shader_template_initialize(RID p_template_shader, const Vector &p_variant_defines, const String &p_general_defines = ""); + void shader_template_initialize(RID p_template_shader, const Vector &p_variant_defines, const String &p_general_defines = ""); + void shader_template_set_variant_enabled(RID p_template_shader, int p_variant, bool p_enabled); + bool shader_template_is_variant_enabled(RID p_template_shader, int p_variant) const; + void shader_template_enable_group(RID p_template_shader, int p_group); + void shader_template_enable_group_on_all(int p_group); + + // shader version + RID shader_template_version_create(RID p_template_shader); + void shader_template_version_free(RID p_template_shader, RID p_version); + void shader_template_version_set_code(RID p_template_shader, RID p_version, const HashMap &p_code, const String &p_uniforms, const String &p_vertex_globals, const String &p_fragment_globals, const Vector &p_custom_defines); + bool shader_template_version_is_valid(RID p_template_shader, RID p_version); + RID shader_template_version_get_shader(RID p_template_shader, RID p_version, int p_variant); + RS::ShaderNativeSourceCode shader_template_version_get_native_source_code(RID p_template_shader, RID p_version); + /* SHADER API */ bool owns_shader(RID p_rid) { return shader_owner.owns(p_rid); }; @@ -395,6 +443,7 @@ class MaterialStorage : public RendererMaterialStorage { virtual void shader_initialize(RID p_shader) override; virtual void shader_free(RID p_rid) override; + virtual void shader_set_shader_template(RID p_shader, RID p_shader_template = RID(), bool p_clear_code = false) override; virtual void shader_set_code(RID p_shader, const String &p_code) override; virtual void shader_set_path_hint(RID p_shader, const String &p_path) override; virtual String shader_get_code(RID p_shader) const override; diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp index 314cbf9aa91c..76fc8187e2e8 100644 --- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp @@ -1644,7 +1644,12 @@ bool ParticlesStorage::particles_is_inactive(RID p_particles) const { /* Particles SHADER */ -void ParticlesStorage::ParticlesShaderData::set_code(const String &p_code) { +void ParticlesStorage::ParticlesShaderData::set_code(const String &p_code, RID p_shader_template) { + // Shader template isn't supported here yet. + if (p_shader_template.is_valid()) { + WARN_PRINT_ONCE("Shader templates are not supported for particle shaders."); + } + ParticlesStorage *particles_storage = ParticlesStorage::get_singleton(); //compile diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.h b/servers/rendering/renderer_rd/storage_rd/particles_storage.h index 33f44f3045a0..9e2962ff0e7a 100644 --- a/servers/rendering/renderer_rd/storage_rd/particles_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.h @@ -357,7 +357,7 @@ class ParticlesStorage : public RendererParticlesStorage { bool userdatas_used[ParticlesShader::MAX_USERDATAS] = {}; uint32_t userdata_count = 0; - virtual void set_code(const String &p_Code); + virtual void set_code(const String &p_Code, RID p_shader_template = RID()); virtual bool is_animated() const; virtual bool casts_shadows() const; virtual RS::ShaderNativeSourceCode get_native_source_code() const; diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index 60fa546e164c..1d3f7155892b 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -225,8 +225,13 @@ class RenderingServerDefault : public RenderingServer { #define ServerName RendererMaterialStorage #define server_name RSG::material_storage + FUNCRIDSPLIT(shader_template) + + FUNC4(shader_template_set_raster_code, RID, const String &, const String &, const String &) + FUNCRIDSPLIT(shader) + FUNC3(shader_set_shader_template, RID, RID, bool) FUNC2(shader_set_code, RID, const String &) FUNC2(shader_set_path_hint, RID, const String &) FUNC1RC(String, shader_get_code, RID) diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index 4eaf7fcb55bd..fdfb7818f34e 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -335,6 +335,7 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = { { TK_CONST, "const", CF_BLOCK | CF_GLOBAL_SPACE | CF_CONST_KEYWORD, {}, {} }, { TK_STRUCT, "struct", CF_GLOBAL_SPACE, {}, {} }, { TK_SHADER_TYPE, "shader_type", CF_SHADER_TYPE, {}, {} }, + { TK_SHADER_TEMPLATE, "shader_template", CF_GLOBAL_SPACE, {}, {} }, { TK_RENDER_MODE, "render_mode", CF_GLOBAL_SPACE, {}, {} }, // uniform qualifiers @@ -1281,6 +1282,7 @@ void ShaderLanguage::clear() { current_function = StringName(); last_name = StringName(); last_type = IDENTIFIER_MAX; + shader_template = ""; current_uniform_group_name = ""; current_uniform_subgroup_name = ""; current_uniform_hint = ShaderNode::Uniform::HINT_NONE; @@ -8346,6 +8348,23 @@ Error ShaderLanguage::_parse_shader(const HashMap &p_f while (tk.type != TK_EOF) { switch (tk.type) { + case TK_SHADER_TEMPLATE: { + tk = _get_token(); + if (tk.type == TK_STRING_CONSTANT) { + shader_template = tk.text; + } else { + _set_error(vformat(RTR("Unexpected token: '%s'."), get_token_text(tk))); + return ERR_PARSE_ERROR; + } + + tk = _get_token(); + if (tk.type == TK_SEMICOLON) { + break; //done + } else { + _set_error(vformat(RTR("Unexpected token: '%s'."), get_token_text(tk))); + return ERR_PARSE_ERROR; + } + } break; case TK_RENDER_MODE: { #ifdef DEBUG_ENABLED keyword_completion_context = CF_UNSPECIFIED; @@ -10270,6 +10289,36 @@ String ShaderLanguage::get_shader_type(const String &p_code) { return String(); } +String ShaderLanguage::get_shader_template(const String &p_code) { + int start_pos = p_code.find("shader_template "); + if (start_pos == -1) { + // No shader template specified, this is ok. + return String(); + } + + start_pos += 16; + char32_t quote = p_code[start_pos]; + while (quote == ' ' || quote == '\t') { + start_pos++; + quote = p_code[start_pos]; + } + + if (quote != '\'' && quote != '"') { + // No quotes, we don't have a string here. + // This will give us a compile error later on. + return String(); + } + + int end_pos = p_code.find_char(quote, start_pos + 1); + if (end_pos == -1) { + // No closing quote? + // This will give us a compile error later on. + return String(); + } + + return p_code.substr(start_pos + 1, end_pos - start_pos - 1); +} + bool ShaderLanguage::is_builtin_func_out_parameter(const String &p_name, int p_param) { int i = 0; while (builtin_func_out_args[i].name) { diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h index 63dca99654d6..9544e02a229c 100644 --- a/servers/rendering/shader_language.h +++ b/servers/rendering/shader_language.h @@ -193,6 +193,7 @@ class ShaderLanguage { TK_CURSOR, TK_ERROR, TK_EOF, + TK_SHADER_TEMPLATE, TK_MAX }; @@ -1000,6 +1001,7 @@ class ShaderLanguage { StringName last_name; bool is_shader_inc = false; + String shader_template; String current_uniform_group_name; String current_uniform_subgroup_name; @@ -1181,6 +1183,7 @@ class ShaderLanguage { void clear(); static String get_shader_type(const String &p_code); + static String get_shader_template(const String &p_code); static bool is_builtin_func_out_parameter(const String &p_name, int p_param); struct ShaderCompileInfo { diff --git a/servers/rendering/storage/material_storage.h b/servers/rendering/storage/material_storage.h index 03feda8abb08..354bec648925 100644 --- a/servers/rendering/storage/material_storage.h +++ b/servers/rendering/storage/material_storage.h @@ -55,11 +55,19 @@ class RendererMaterialStorage { virtual void global_shader_parameters_instance_free(RID p_instance) = 0; virtual void global_shader_parameters_instance_update(RID p_instance, int p_index, const Variant &p_value, int p_flags_count = 0) = 0; + /* SHADER TEMPLATE API */ + virtual RID shader_template_allocate() = 0; + virtual void shader_template_initialize(RID p_rid) = 0; + virtual void shader_template_free(RID p_rid) = 0; + + virtual void shader_template_set_raster_code(RID p_template_shader, const String &p_vertex_code, const String &p_fragment_code, const String &p_name) = 0; + /* SHADER API */ virtual RID shader_allocate() = 0; virtual void shader_initialize(RID p_rid) = 0; virtual void shader_free(RID p_rid) = 0; + virtual void shader_set_shader_template(RID p_shader, RID p_shader_template = RID(), bool p_clear_code = false) = 0; virtual void shader_set_code(RID p_shader, const String &p_code) = 0; virtual void shader_set_path_hint(RID p_shader, const String &p_path) = 0; virtual String shader_get_code(RID p_shader) const = 0; diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 1848d5602ef3..be4f251398f3 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -2276,9 +2276,15 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(CUBEMAP_LAYER_FRONT); BIND_ENUM_CONSTANT(CUBEMAP_LAYER_BACK); + /* SHADER TEMPLATE */ + + ClassDB::bind_method(D_METHOD("shader_template_create"), &RenderingServer::shader_template_create); + ClassDB::bind_method(D_METHOD("shader_template_set_raster_code", "shader_template", "vertex_code", "fragment_code", "name"), &RenderingServer::shader_template_set_raster_code); + /* SHADER */ ClassDB::bind_method(D_METHOD("shader_create"), &RenderingServer::shader_create); + ClassDB::bind_method(D_METHOD("shader_set_shader_template", "shader", "shader_template", "clear_code"), &RenderingServer::shader_set_shader_template, DEFVAL(RID()), DEFVAL(false)); ClassDB::bind_method(D_METHOD("shader_set_code", "shader", "code"), &RenderingServer::shader_set_code); ClassDB::bind_method(D_METHOD("shader_set_path_hint", "shader", "path"), &RenderingServer::shader_set_path_hint); ClassDB::bind_method(D_METHOD("shader_get_code", "shader"), &RenderingServer::shader_get_code); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 62ca6b3b6dc6..2fca6245da4c 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -189,6 +189,12 @@ class RenderingServer : public Object { virtual RID texture_get_rd_texture(RID p_texture, bool p_srgb = false) const = 0; virtual uint64_t texture_get_native_handle(RID p_texture, bool p_srgb = false) const = 0; + /* SHADER TEMPLATE API */ + + virtual RID shader_template_create() = 0; + + virtual void shader_template_set_raster_code(RID p_shader_template, const String &p_vertex_code, const String &p_fragment_code, const String &p_name) = 0; + /* SHADER API */ enum ShaderMode { @@ -202,6 +208,7 @@ class RenderingServer : public Object { virtual RID shader_create() = 0; + virtual void shader_set_shader_template(RID p_shader, RID p_shader_template = RID(), bool p_clear_code = false) = 0; virtual void shader_set_code(RID p_shader, const String &p_code) = 0; virtual void shader_set_path_hint(RID p_shader, const String &p_path) = 0; virtual String shader_get_code(RID p_shader) const = 0;