Skip to content

Commit

Permalink
Add custom shader template feature
Browse files Browse the repository at this point in the history
  • Loading branch information
BastiaanOlij committed Jul 25, 2024
1 parent c698698 commit a4b05da
Show file tree
Hide file tree
Showing 48 changed files with 1,651 additions and 589 deletions.
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 @@ -3261,6 +3261,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 @@ -3282,6 +3283,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;shader_type spatial; #[vertex] #[fragment] &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 @@ -2128,6 +2128,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 @@ -2158,6 +2189,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 @@ -2226,7 +2266,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 @@ -2532,7 +2572,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 @@ -2699,7 +2744,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 @@ -2841,7 +2891,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 @@ -3119,7 +3174,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
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

0 comments on commit a4b05da

Please sign in to comment.