Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Custom shader templates #94427

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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions doc/classes/BaseMaterial3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,10 @@
<member name="roughness_texture_channel" type="int" setter="set_roughness_texture_channel" getter="get_roughness_texture_channel" enum="BaseMaterial3D.TextureChannel" default="0">
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.
</member>
<member name="shader_template" type="ShaderTemplate" setter="set_shader_template" getter="get_shader_template">
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.
</member>
<member name="shading_mode" type="int" setter="set_shading_mode" getter="get_shading_mode" enum="BaseMaterial3D.ShadingMode" default="1">
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.
Expand Down
29 changes: 29 additions & 0 deletions doc/classes/RenderingServer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3330,6 +3330,7 @@
<param index="1" name="code" type="String" />
<description>
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!
</description>
</method>
<method name="shader_set_default_texture_parameter">
Expand All @@ -3351,6 +3352,34 @@
Sets the path hint for the specified shader. This should generally match the [Shader] resource's [member Resource.resource_path].
</description>
</method>
<method name="shader_set_shader_template">
<return type="void" />
<param index="0" name="shader" type="RID" />
<param index="1" name="shader_template" type="RID" default="RID()" />
<param index="2" name="clear_code" type="bool" default="false" />
<description>
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.
</description>
</method>
<method name="shader_template_create">
<return type="RID" />
<description>
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.
</description>
</method>
<method name="shader_template_set_raster_code">
<return type="void" />
<param index="0" name="shader_template" type="RID" />
<param index="1" name="vertex_code" type="String" />
<param index="2" name="fragment_code" type="String" />
<param index="3" name="name" type="String" />
<description>
Set the vertex and fragment code for the shader template. [param name] is used for caching this shader.
</description>
</method>
<method name="skeleton_allocate_data">
<return type="void" />
<param index="0" name="skeleton" type="RID" />
Expand Down
25 changes: 25 additions & 0 deletions doc/classes/ShaderTemplate.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="ShaderTemplate" inherits="Resource" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A shader template contains the template GLSL code into which user shader code is injected.
</brief_description>
<description>
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.
</description>
<tutorials>
</tutorials>
<methods>
<method name="get_mode" qualifiers="const">
<return type="int" enum="Shader.Mode" />
<description>
Get shader mode for this shader template.
</description>
</method>
</methods>
<members>
<member name="code" type="String" setter="set_code" getter="get_code" default="&quot;&quot;">
The shader code for this shader template.
</member>
</members>
</class>
70 changes: 65 additions & 5 deletions drivers/gles3/storage/material_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -2530,7 +2570,12 @@ LocalVector<ShaderGLES3::TextureUniformData> 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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
35 changes: 30 additions & 5 deletions drivers/gles3/storage/material_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ struct ShaderData {
virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *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(); }
Expand All @@ -73,10 +73,19 @@ struct ShaderData {

typedef ShaderData *(*ShaderDataRequestFunction)();

struct Shader;
struct Material;

struct ShaderTemplate {
ShaderGLES3 *shader;
HashSet<Shader *> owners;

void cleanup();
};

struct Shader {
ShaderData *data = nullptr;
RID shader_template;
String code;
String path_hint;
RS::ShaderMode mode;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -482,6 +491,10 @@ class MaterialStorage : public RendererMaterialStorage {

/* SHADER API */

mutable RID_Owner<ShaderTemplate, true> shader_template_owner;

/* SHADER API */

ShaderDataRequestFunction shader_data_request_func[RS::SHADER_MAX];
mutable RID_Owner<Shader, true> shader_owner;

Expand Down Expand Up @@ -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); };
Expand All @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions main/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
1 change: 1 addition & 0 deletions main/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
20 changes: 20 additions & 0 deletions scene/register_scene_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -313,6 +314,9 @@ static Ref<ResourceFormatLoaderCompressedTexture2D> resource_loader_stream_textu
static Ref<ResourceFormatLoaderCompressedTextureLayered> resource_loader_texture_layered;
static Ref<ResourceFormatLoaderCompressedTexture3D> resource_loader_texture_3d;

static Ref<ResourceFormatSaverShaderTemplate> resource_saver_shader_template;
static Ref<ResourceFormatLoaderShaderTemplate> resource_loader_shader_template;

static Ref<ResourceFormatSaverShader> resource_saver_shader;
static Ref<ResourceFormatLoaderShader> resource_loader_shader;

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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();

Expand Down
Loading
Loading