Skip to content

Commit

Permalink
Add support for struct uniforms in shaders
Browse files Browse the repository at this point in the history
  • Loading branch information
Chaosus committed Jun 28, 2024
1 parent cae2f85 commit 88c60bc
Show file tree
Hide file tree
Showing 28 changed files with 767 additions and 85 deletions.
29 changes: 27 additions & 2 deletions drivers/gles3/shader_gles3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,20 @@ void ShaderGLES3::_add_stage(const char *p_code, StageType p_stage_type) {

StageTemplate::Chunk chunk;

if (l.begins_with("#GLOBALS")) {
if (l.begins_with("#STRUCTS")) {
switch (p_stage_type) {
case STAGE_TYPE_VERTEX:
chunk.type = StageTemplate::Chunk::TYPE_VERTEX_STRUCTS;
break;
case STAGE_TYPE_FRAGMENT:
chunk.type = StageTemplate::Chunk::TYPE_FRAGMENT_STRUCTS;
break;
default: {
}
}

push_chunk = true;
} else if (l.begins_with("#GLOBALS")) {
switch (p_stage_type) {
case STAGE_TYPE_VERTEX:
chunk.type = StageTemplate::Chunk::TYPE_VERTEX_GLOBALS;
Expand Down Expand Up @@ -224,9 +237,15 @@ void ShaderGLES3::_build_variant_code(StringBuilder &builder, uint32_t p_variant
case StageTemplate::Chunk::TYPE_MATERIAL_UNIFORMS: {
builder.append(p_version->uniforms.get_data()); //uniforms (same for vertex and fragment)
} break;
case StageTemplate::Chunk::TYPE_VERTEX_STRUCTS: {
builder.append(p_version->vertex_structs.get_data()); // vertex structs
} break;
case StageTemplate::Chunk::TYPE_VERTEX_GLOBALS: {
builder.append(p_version->vertex_globals.get_data()); // vertex globals
} break;
case StageTemplate::Chunk::TYPE_FRAGMENT_STRUCTS: {
builder.append(p_version->fragment_structs.get_data()); // fragment structs
} break;
case StageTemplate::Chunk::TYPE_FRAGMENT_GLOBALS: {
builder.append(p_version->fragment_globals.get_data()); // fragment globals
} break;
Expand Down Expand Up @@ -503,8 +522,12 @@ String ShaderGLES3::_version_get_sha1(Version *p_version) const {

hash_build.append("[uniforms]");
hash_build.append(p_version->uniforms.get_data());
hash_build.append("[vertex_structs]");
hash_build.append(p_version->vertex_structs.get_data());
hash_build.append("[vertex_globals]");
hash_build.append(p_version->vertex_globals.get_data());
hash_build.append("[fragment_structs]");
hash_build.append(p_version->fragment_structs.get_data());
hash_build.append("[fragment_globals]");
hash_build.append(p_version->fragment_globals.get_data());

Expand Down Expand Up @@ -714,13 +737,15 @@ void ShaderGLES3::_initialize_version(Version *p_version) {
}
}

void ShaderGLES3::version_set_code(RID p_version, const HashMap<String, String> &p_code, const String &p_uniforms, const String &p_vertex_globals, const String &p_fragment_globals, const Vector<String> &p_custom_defines, const LocalVector<ShaderGLES3::TextureUniformData> &p_texture_uniforms, bool p_initialize) {
void ShaderGLES3::version_set_code(RID p_version, const HashMap<String, String> &p_code, const String &p_uniforms, const String &p_vertex_structs, const String &p_vertex_globals, const String &p_fragment_structs, const String &p_fragment_globals, const Vector<String> &p_custom_defines, const LocalVector<ShaderGLES3::TextureUniformData> &p_texture_uniforms, bool p_initialize) {
Version *version = version_owner.get_or_null(p_version);
ERR_FAIL_NULL(version);

_clear_version(version); //clear if existing

version->vertex_structs = p_vertex_structs.utf8();
version->vertex_globals = p_vertex_globals.utf8();
version->fragment_structs = p_fragment_structs.utf8();
version->fragment_globals = p_fragment_globals.utf8();
version->uniforms = p_uniforms.utf8();
version->code_sections.clear();
Expand Down
6 changes: 5 additions & 1 deletion drivers/gles3/shader_gles3.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ class ShaderGLES3 {
struct Version {
LocalVector<TextureUniformData> texture_uniforms;
CharString uniforms;
CharString vertex_structs;
CharString vertex_globals;
CharString fragment_structs;
CharString fragment_globals;
HashMap<StringName, CharString> code_sections;
Vector<CharString> custom_defines;
Expand Down Expand Up @@ -124,7 +126,9 @@ class ShaderGLES3 {
struct Chunk {
enum Type {
TYPE_MATERIAL_UNIFORMS,
TYPE_VERTEX_STRUCTS,
TYPE_VERTEX_GLOBALS,
TYPE_FRAGMENT_STRUCTS,
TYPE_FRAGMENT_GLOBALS,
TYPE_CODE,
TYPE_TEXT
Expand Down Expand Up @@ -244,7 +248,7 @@ class ShaderGLES3 {
public:
RID version_create();

void version_set_code(RID p_version, const HashMap<String, String> &p_code, const String &p_uniforms, const String &p_vertex_globals, const String &p_fragment_globals, const Vector<String> &p_custom_defines, const LocalVector<ShaderGLES3::TextureUniformData> &p_texture_uniforms, bool p_initialize = false);
void version_set_code(RID p_version, const HashMap<String, String> &p_code, const String &p_uniforms, const String &p_vertex_structs, const String &p_vertex_globals, const String &p_fragment_structs, const String &p_fragment_globals, const Vector<String> &p_custom_defines, const LocalVector<ShaderGLES3::TextureUniformData> &p_texture_uniforms, bool p_initialize = false);

bool version_is_valid(RID p_version);

Expand Down
6 changes: 6 additions & 0 deletions drivers/gles3/shaders/canvas.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ flat out vec4 varying_E;
flat out uvec2 varying_F;
flat out uvec4 varying_G;

/* clang-format on */
#STRUCTS
/* clang-format off */

// This needs to be outside clang-format so the ubo comment is in the right place
#ifdef MATERIAL_UNIFORMS_USED
layout(std140) uniform MaterialUniforms{ //ubo:4
Expand Down Expand Up @@ -339,6 +343,8 @@ uniform sampler2D color_texture; //texunit:0

layout(location = 0) out vec4 frag_color;

#STRUCTS

/* clang-format off */
// This needs to be outside clang-format so the ubo comment is in the right place
#ifdef MATERIAL_UNIFORMS_USED
Expand Down
4 changes: 4 additions & 0 deletions drivers/gles3/shaders/particles.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ layout(std140) uniform GlobalShaderUniformData { //ubo:1
vec4 global_shader_uniforms[MAX_GLOBAL_SHADER_UNIFORMS];
};

/* clang-format on */
#STRUCTS
/* clang-format off */

// This needs to be outside clang-format so the ubo comment is in the right place
#ifdef MATERIAL_UNIFORMS_USED
layout(std140) uniform MaterialUniforms{ //ubo:2
Expand Down
12 changes: 12 additions & 0 deletions drivers/gles3/shaders/scene.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,12 @@ out highp vec4 shadow_coord4;
#endif //LIGHT_USE_PSSM4
#endif

/* clang-format off */

#STRUCTS

/* clang-format on */

#ifdef MATERIAL_UNIFORMS_USED

/* clang-format off */
Expand Down Expand Up @@ -669,6 +675,12 @@ layout(std140) uniform GlobalShaderUniformData { //ubo:1
vec4 global_shader_uniforms[MAX_GLOBAL_SHADER_UNIFORMS];
};

/* clang-format off */

#STRUCTS

/* clang-format on */

/* Material Uniforms */
#ifdef MATERIAL_UNIFORMS_USED

Expand Down
2 changes: 2 additions & 0 deletions drivers/gles3/shaders/sky.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ layout(std140) uniform DirectionalLights { //ubo:4
}
directional_lights;

#STRUCTS

/* clang-format off */

#ifdef MATERIAL_UNIFORMS_USED
Expand Down
95 changes: 73 additions & 22 deletions drivers/gles3/storage/material_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,15 @@ void ShaderData::set_default_texture_parameter(const StringName &p_name, RID p_t
Variant ShaderData::get_default_parameter(const StringName &p_parameter) const {
if (uniforms.has(p_parameter)) {
ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];

if (uniform.type == ShaderLanguage::TYPE_STRUCT) {
Dictionary dict;
for (const ShaderLanguage::ShaderNode::Uniform::Member &member : uniform.members) {
dict[member.name] = ShaderLanguage::get_default_datatype_value(member.type, member.array_size, ShaderLanguage::ShaderNode::Uniform::HINT_NONE);
}
return dict;
}

Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
}
Expand Down Expand Up @@ -755,6 +764,17 @@ void MaterialData::update_uniform_buffer(const HashMap<StringName, ShaderLanguag
if ((size % m) != 0U) {
size += m - (size % m);
}
} else if (E.value.type == ShaderLanguage::TYPE_STRUCT) {
// The following code enforces a 16-byte alignment of struct.
for (const ShaderLanguage::ShaderNode::Uniform::Member &member : E.value.members) {
int member_array_size = MAX(1, member.array_size);
uint32_t member_size = ShaderLanguage::get_datatype_size(member.type) * member_array_size;
int m = (16 * member_array_size);
if ((member_size % m) != 0U) {
member_size += m - (member_size % m);
}
size += member_size;
}
} else {
size = ShaderLanguage::get_datatype_size(E.value.type);
}
Expand All @@ -764,22 +784,53 @@ void MaterialData::update_uniform_buffer(const HashMap<StringName, ShaderLanguag
HashMap<StringName, Variant>::ConstIterator V = p_parameters.find(E.key);

if (V) {
//user provided
_fill_std140_variant_ubo_value(E.value.type, E.value.array_size, V->value, data);
// User provided.
if (E.value.type == ShaderLanguage::TYPE_STRUCT) {
Dictionary dict = (Dictionary)V->value;

uint32_t sub_offset = 0U;
for (const ShaderLanguage::ShaderNode::Uniform::Member &member : E.value.members) {
if (dict.has(member.name)) {
_fill_std140_variant_ubo_value(member.type, member.array_size, dict[member.name], &data[sub_offset]);
} else {
// Zero because it was not provided.
_fill_std140_ubo_empty(member.type, member.array_size, &data[sub_offset]);
}

int member_array_size = MAX(1, member.array_size);
uint32_t member_size = ShaderLanguage::get_datatype_size(member.type) * member_array_size;
int m = (16 * member_array_size);
if ((member_size % m) != 0) {
member_size += m - (member_size % m);
}
sub_offset += member_size;
}
} else {
_fill_std140_variant_ubo_value(E.value.type, E.value.array_size, V->value, data);
}
} else if (E.value.default_value.size()) {
//default value
// Default value.
_fill_std140_ubo_value(E.value.type, E.value.default_value, data);
//value=E.value.default_value;
} else {
//zero because it was not provided
if ((E.value.type == ShaderLanguage::TYPE_VEC3 || E.value.type == ShaderLanguage::TYPE_VEC4) && E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_SOURCE_COLOR) {
//colors must be set as black, with alpha as 1.0
_fill_std140_variant_ubo_value(E.value.type, E.value.array_size, Color(0, 0, 0, 1), data);
} else {
//else just zero it out
_fill_std140_ubo_empty(E.value.type, E.value.array_size, data);
} else if (E.value.type == ShaderLanguage::TYPE_STRUCT) {
uint32_t sub_offset = 0U;
for (const ShaderLanguage::ShaderNode::Uniform::Member &member : E.value.members) {
// Zero because it was not provided.
_fill_std140_ubo_empty(member.type, member.array_size, &data[sub_offset]);

int member_array_size = MAX(1, member.array_size);
uint32_t member_size = ShaderLanguage::get_datatype_size(member.type) * member_array_size;
int m = (16 * member_array_size);
if ((member_size % m) != 0) {
member_size += m - (member_size % m);
}
sub_offset += member_size;
}
} else if ((E.value.type == ShaderLanguage::TYPE_VEC3 || E.value.type == ShaderLanguage::TYPE_VEC4) && E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_SOURCE_COLOR) {
// Colors must be set as black, with alpha as 1.0
_fill_std140_variant_ubo_value(E.value.type, E.value.array_size, Color(0, 0, 0, 1), data);
} else {
// Otherwise, just zero it out
_fill_std140_ubo_empty(E.value.type, E.value.array_size, data);
}
}

Expand Down Expand Up @@ -2599,13 +2650,13 @@ void CanvasShaderData::set_code(const String &p_code) {
}

print_line("\n**uniforms:\n" + gen_code.uniforms);
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]);
print_line("\n**vertex_globals:\n" + gen_code.stage_structs[ShaderCompiler::STAGE_VERTEX] + gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX]);
print_line("\n**fragment_globals:\n" + gen_code.stage_structs[ShaderCompiler::STAGE_FRAGMENT] + gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT]);
#endif

LocalVector<ShaderGLES3::TextureUniformData> texture_uniform_data = get_texture_uniform_data(gen_code.texture_uniforms);

MaterialStorage::get_singleton()->shaders.canvas_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, texture_uniform_data);
MaterialStorage::get_singleton()->shaders.canvas_shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_structs[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_structs[ShaderCompiler::STAGE_FRAGMENT], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines, texture_uniform_data);
ERR_FAIL_COND(!MaterialStorage::get_singleton()->shaders.canvas_shader.version_is_valid(version));

vertex_input_mask = RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_COLOR | RS::ARRAY_FORMAT_TEX_UV;
Expand Down Expand Up @@ -2771,13 +2822,13 @@ void SkyShaderData::set_code(const String &p_code) {
}

print_line("\n**uniforms:\n" + gen_code.uniforms);
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]);
print_line("\n**vertex_globals:\n" + gen_code.stage_structs[ShaderCompiler::STAGE_VERTEX] + gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX]);
print_line("\n**fragment_globals:\n" + gen_code.stage_structs[ShaderCompiler::STAGE_FRAGMENT] + gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT]);
#endif

LocalVector<ShaderGLES3::TextureUniformData> texture_uniform_data = get_texture_uniform_data(gen_code.texture_uniforms);

MaterialStorage::get_singleton()->shaders.sky_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, texture_uniform_data);
MaterialStorage::get_singleton()->shaders.sky_shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_structs[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_structs[ShaderCompiler::STAGE_FRAGMENT], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines, texture_uniform_data);
ERR_FAIL_COND(!MaterialStorage::get_singleton()->shaders.sky_shader.version_is_valid(version));

ubo_size = gen_code.uniform_total_size;
Expand Down Expand Up @@ -3031,13 +3082,13 @@ void SceneShaderData::set_code(const String &p_code) {
}

print_line("\n**uniforms:\n" + gen_code.uniforms);
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]);
print_line("\n**vertex_globals:\n" + gen_code.stage_structs[ShaderCompiler::STAGE_VERTEX] + gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX]);
print_line("\n**fragment_globals:\n" + gen_code.stage_structs[ShaderCompiler::STAGE_FRAGMENT] + gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT]);
#endif

LocalVector<ShaderGLES3::TextureUniformData> texture_uniform_data = get_texture_uniform_data(gen_code.texture_uniforms);

MaterialStorage::get_singleton()->shaders.scene_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, texture_uniform_data);
MaterialStorage::get_singleton()->shaders.scene_shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_structs[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_structs[ShaderCompiler::STAGE_FRAGMENT], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines, texture_uniform_data);
ERR_FAIL_COND(!MaterialStorage::get_singleton()->shaders.scene_shader.version_is_valid(version));

ubo_size = gen_code.uniform_total_size;
Expand Down Expand Up @@ -3165,7 +3216,7 @@ void ParticlesShaderData::set_code(const String &p_code) {

LocalVector<ShaderGLES3::TextureUniformData> texture_uniform_data = get_texture_uniform_data(gen_code.texture_uniforms);

MaterialStorage::get_singleton()->shaders.particles_process_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, texture_uniform_data);
MaterialStorage::get_singleton()->shaders.particles_process_shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_structs[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_structs[ShaderCompiler::STAGE_FRAGMENT], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines, texture_uniform_data);
ERR_FAIL_COND(!MaterialStorage::get_singleton()->shaders.particles_process_shader.version_is_valid(version));

ubo_size = gen_code.uniform_total_size;
Expand Down
Loading

0 comments on commit 88c60bc

Please sign in to comment.