Skip to content

Commit

Permalink
Adding ability to include build-in include files (precursor to custom…
Browse files Browse the repository at this point in the history
… shader templates)
  • Loading branch information
BastiaanOlij committed Jul 22, 2024
1 parent e25f3c0 commit c698698
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 8 deletions.
10 changes: 10 additions & 0 deletions servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
#include "core/os/os.h"
#include "renderer_compositor_rd.h"
#include "servers/rendering/renderer_rd/environment/fog.h"
#include "servers/rendering/renderer_rd/shaders/decal_data_inc.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/light_data_inc.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/scene_data_inc.glsl.gen.h"
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
#include "servers/rendering/renderer_rd/storage_rd/texture_storage.h"
#include "servers/rendering/rendering_server_default.h"
Expand Down Expand Up @@ -1441,6 +1444,13 @@ void RendererSceneRenderRD::init() {
/* Forward ID */
forward_id_storage = create_forward_id_storage();

/* Register the include files we make available by default to our users */
{
RenderingDevice::register_built_in_include_file("decal_data_inc.glsl", decal_data_inc_shader_glsl);
RenderingDevice::register_built_in_include_file("light_data_inc.glsl", light_data_inc_shader_glsl);
RenderingDevice::register_built_in_include_file("scene_data_inc.glsl", scene_data_inc_shader_glsl);
}

/* SKY SHADER */

sky.init();
Expand Down
10 changes: 7 additions & 3 deletions servers/rendering/renderer_rd/shaders/SCsub
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,20 @@
Import("env")

if "RD_GLSL" in env["BUILDERS"]:
# find all include files
# find just the include files
gl_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"])

# compile shaders
# compile include files
for glsl_file in gl_include_files:
env.GLSL_HEADER(glsl_file)

# compile RD shader
for glsl_file in glsl_files:
env.RD_GLSL(glsl_file)

Expand Down
70 changes: 69 additions & 1 deletion servers/rendering/rendering_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,12 @@ void RenderingDevice::_free_dependencies(RID p_id) {
}
}

/*******************************/
/**** SHADER INFRASTRUCTURE ****/
/*******************************/

HashMap<String, String> RenderingDevice::build_in_includes;

void RenderingDevice::shader_set_compile_to_spirv_function(ShaderCompileToSPIRVFunction p_function) {
compile_to_spirv_function = p_function;
}
Expand All @@ -188,6 +194,20 @@ void RenderingDevice::shader_set_get_cache_key_function(ShaderSPIRVGetCacheKeyFu
get_spirv_cache_key_function = p_function;
}

void RenderingDevice::register_built_in_include_file(const String &p_filename, const String &p_shader_code) {
build_in_includes[p_filename] = p_shader_code;
}

bool RenderingDevice::has_built_in_include_file(const String &p_filename) {
return build_in_includes.has(p_filename);
}

String RenderingDevice::get_built_in_include_file(const String &p_filename) {
const String *ptr = build_in_includes.getptr(p_filename);

return ptr ? *ptr : String();
}

Vector<uint8_t> RenderingDevice::shader_compile_spirv_from_source(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error, bool p_allow_cache) {
if (p_allow_cache && cache_function) {
Vector<uint8_t> cache = cache_function(p_stage, p_source_code, p_language);
Expand All @@ -198,7 +218,55 @@ Vector<uint8_t> RenderingDevice::shader_compile_spirv_from_source(ShaderStage p_

ERR_FAIL_NULL_V(compile_to_spirv_function, Vector<uint8_t>());

return compile_to_spirv_function(p_stage, p_source_code, p_language, r_error, this);
// Check for build in includes
const String include = "#include \"";
const String quote = "\"";
const int include_len = include.length();
int pos = p_source_code.find(include);
int prev_pos = 0;
if (pos >= 0) {
String parsed_code;

while (pos >= 0) {
// Add what came before.
parsed_code += p_source_code.substr(prev_pos, pos - prev_pos);

if (pos > 0 && p_source_code[pos - 1] != '\n' && p_source_code[pos - 1] != '\r') {
// Not at the start of our line? Just skip this one.
parsed_code += include;
pos += include_len;
} else {
int end_pos = p_source_code.find(quote, pos + include_len);
if (end_pos == -1) {
// No closing quote? Just skip this one.
parsed_code += include;
pos += include_len;
} else {
String include_file = p_source_code.substr(pos + include_len, end_pos - (pos + include_len));

if (build_in_includes.has(include_file)) {
parsed_code += build_in_includes[include_file];
} else {
// Just add it back in, this will cause a compile error to alert the user.
parsed_code += include + include_file + quote;
}

pos = end_pos + 1;
}
}

// Find our next one.
prev_pos = pos;
pos = p_source_code.find(include, pos);
}

// Add our remainder.
parsed_code += p_source_code.substr(prev_pos);

return compile_to_spirv_function(p_stage, parsed_code, p_language, r_error, this);
} else {
return compile_to_spirv_function(p_stage, p_source_code, p_language, r_error, this);
}
}

String RenderingDevice::shader_get_spirv_cache_key() const {
Expand Down
7 changes: 7 additions & 0 deletions servers/rendering/rendering_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ class RenderingDevice : public RenderingDeviceCommons {
typedef void (*InvalidationCallback)(void *);

private:
// build in includes
static HashMap<String, String> build_in_includes;

static ShaderCompileToSPIRVFunction compile_to_spirv_function;
static ShaderCacheFunction cache_function;
static ShaderSPIRVGetCacheKeyFunction get_spirv_cache_key_function;
Expand Down Expand Up @@ -841,6 +844,10 @@ class RenderingDevice : public RenderingDeviceCommons {
static void shader_set_spirv_cache_function(ShaderCacheFunction p_function);
static void shader_set_get_cache_key_function(ShaderSPIRVGetCacheKeyFunction p_function);

static void register_built_in_include_file(const String &p_filename, const String &p_shader_code);
static bool has_built_in_include_file(const String &p_filename);
static String get_built_in_include_file(const String &p_filename);

String shader_get_binary_cache_key() const;
Vector<uint8_t> shader_compile_binary_from_spirv(const Vector<ShaderStageSPIRVData> &p_spirv, const String &p_shader_name = "");

Expand Down
12 changes: 8 additions & 4 deletions servers/rendering/rendering_device_binds.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,15 @@ Error RDShaderFile::parse_versions_from_text(const String &p_text, const String
break;
}
include = include.substr(1, include.length() - 2).strip_edges();
String include_text = p_include_func(include, p_include_func_userdata);
if (!include_text.is_empty()) {
stage_code[stage] += "\n" + include_text + "\n";
if (RD::has_built_in_include_file(include)) {
stage_code[stage] += "\n" + RD::get_built_in_include_file(include) + "\n";
} else {
base_error = "#include failed for file '" + include + "'";
String include_text = p_include_func(include, p_include_func_userdata);
if (!include_text.is_empty()) {
stage_code[stage] += "\n" + include_text + "\n";
} else {
base_error = "#include failed for file '" + include + "'";
}
}
} else {
base_error = "#include used, but no include function provided.";
Expand Down

0 comments on commit c698698

Please sign in to comment.