Implement shader uniform groups/subgroups

This commit is contained in:
Yuri Rubinsky 2022-07-13 11:31:27 +03:00
parent c3dc887c41
commit 886c2d9681
13 changed files with 298 additions and 8 deletions

View file

@ -2900,7 +2900,22 @@ void CanvasShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
}
}
String last_group;
for (const KeyValue<int, StringName> &E : order) {
String group = uniforms[E.value].group;
if (!uniforms[E.value].subgroup.is_empty()) {
group += "::" + uniforms[E.value].subgroup;
}
if (group != last_group) {
PropertyInfo pi;
pi.usage = PROPERTY_USAGE_GROUP;
pi.name = group;
p_param_list->push_back(pi);
last_group = group;
}
PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
pi.name = E.value;
p_param_list->push_back(pi);
@ -3123,7 +3138,22 @@ void SkyShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
}
}
String last_group;
for (const KeyValue<int, StringName> &E : order) {
String group = uniforms[E.value].group;
if (!uniforms[E.value].subgroup.is_empty()) {
group += "::" + uniforms[E.value].subgroup;
}
if (group != last_group) {
PropertyInfo pi;
pi.usage = PROPERTY_USAGE_GROUP;
pi.name = group;
p_param_list->push_back(pi);
last_group = group;
}
PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
pi.name = E.value;
p_param_list->push_back(pi);
@ -3433,7 +3463,22 @@ void SceneShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
}
}
String last_group;
for (const KeyValue<int, StringName> &E : order) {
String group = uniforms[E.value].group;
if (!uniforms[E.value].subgroup.is_empty()) {
group += "::" + uniforms[E.value].subgroup;
}
if (group != last_group) {
PropertyInfo pi;
pi.usage = PROPERTY_USAGE_GROUP;
pi.name = group;
p_param_list->push_back(pi);
last_group = group;
}
PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
pi.name = E.value;
p_param_list->push_back(pi);

View file

@ -202,7 +202,98 @@ bool ShaderMaterial::_get(const StringName &p_name, Variant &r_ret) const {
void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const {
if (!shader.is_null()) {
shader->get_param_list(p_list);
List<PropertyInfo> list;
shader->get_param_list(&list, true);
HashMap<String, HashMap<String, List<PropertyInfo>>> groups;
{
HashMap<String, List<PropertyInfo>> none_subgroup;
none_subgroup.insert("<None>", List<PropertyInfo>());
groups.insert("<None>", none_subgroup);
}
String last_group = "<None>";
String last_subgroup = "<None>";
bool is_none_group_undefined = true;
bool is_none_group = true;
for (List<PropertyInfo>::Element *E = list.front(); E; E = E->next()) {
if (E->get().usage == PROPERTY_USAGE_GROUP) {
if (!E->get().name.is_empty()) {
Vector<String> vgroup = E->get().name.split("::");
last_group = vgroup[0];
if (vgroup.size() > 1) {
last_subgroup = vgroup[1];
} else {
last_subgroup = "<None>";
}
is_none_group = false;
if (!groups.has(last_group)) {
PropertyInfo info;
info.usage = PROPERTY_USAGE_GROUP;
info.name = last_group;
List<PropertyInfo> none_subgroup;
none_subgroup.push_back(info);
HashMap<String, List<PropertyInfo>> subgroup_map;
subgroup_map.insert("<None>", none_subgroup);
groups.insert(last_group, subgroup_map);
}
if (!groups[last_group].has(last_subgroup)) {
PropertyInfo info;
info.usage = PROPERTY_USAGE_SUBGROUP;
info.name = last_subgroup;
List<PropertyInfo> subgroup;
subgroup.push_back(info);
groups[last_group].insert(last_subgroup, subgroup);
}
} else {
last_group = "<None>";
last_subgroup = "<None>";
is_none_group = true;
}
continue; // Pass group.
}
if (is_none_group_undefined && is_none_group) {
is_none_group_undefined = false;
PropertyInfo info;
info.usage = PROPERTY_USAGE_GROUP;
info.name = "Shader Param";
groups["<None>"]["<None>"].push_back(info);
}
PropertyInfo info = E->get();
info.name = info.name;
groups[last_group][last_subgroup].push_back(info);
}
// Sort groups alphabetically.
List<UniformProp> props;
for (HashMap<String, HashMap<String, List<PropertyInfo>>>::Iterator group = groups.begin(); group; ++group) {
for (HashMap<String, List<PropertyInfo>>::Iterator subgroup = group->value.begin(); subgroup; ++subgroup) {
for (List<PropertyInfo>::Element *item = subgroup->value.front(); item; item = item->next()) {
if (subgroup->key == "<None>") {
props.push_back({ group->key, item->get() });
} else {
props.push_back({ group->key + "::" + subgroup->key, item->get() });
}
}
}
}
props.sort_custom<UniformPropComparator>();
for (List<UniformProp>::Element *E = props.front(); E; E = E->next()) {
p_list->push_back(E->get().info);
}
}
}

View file

@ -84,6 +84,17 @@ class ShaderMaterial : public Material {
HashMap<StringName, Variant> param_cache;
struct UniformProp {
String str;
PropertyInfo info;
};
struct UniformPropComparator {
bool operator()(const UniformProp &p_a, const UniformProp &p_b) const {
return p_a.str.naturalnocasecmp_to(p_b.str) < 0;
}
};
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;

View file

@ -103,7 +103,7 @@ String Shader::get_code() const {
return code;
}
void Shader::get_param_list(List<PropertyInfo> *p_params) const {
void Shader::get_param_list(List<PropertyInfo> *p_params, bool p_get_groups) const {
_update_shader();
List<PropertyInfo> local;
@ -112,12 +112,16 @@ void Shader::get_param_list(List<PropertyInfo> *p_params) const {
params_cache_dirty = false;
for (PropertyInfo &pi : local) {
if (default_textures.has(pi.name)) { //do not show default textures
bool is_group = pi.usage == PROPERTY_USAGE_GROUP || pi.usage == PROPERTY_USAGE_SUBGROUP;
if (!p_get_groups && is_group) {
continue;
}
String original_name = pi.name;
pi.name = "shader_param/" + pi.name;
params_cache[pi.name] = original_name;
if (!is_group) {
if (default_textures.has(pi.name)) { //do not show default textures
continue;
}
params_cache[pi.name] = pi.name;
}
if (p_params) {
//small little hack
if (pi.type == Variant::RID) {

View file

@ -78,7 +78,7 @@ public:
void set_code(const String &p_code);
String get_code() const;
void get_param_list(List<PropertyInfo> *p_params) const;
void get_param_list(List<PropertyInfo> *p_params, bool p_get_groups = false) const;
bool has_param(const StringName &p_param) const;
void set_default_texture_param(const StringName &p_param, const Ref<Texture2D> &p_texture, int p_index = 0);

View file

@ -393,7 +393,22 @@ void Fog::FogShaderData::get_param_list(List<PropertyInfo> *p_param_list) const
}
}
String last_group;
for (const KeyValue<int, StringName> &E : order) {
String group = uniforms[E.value].group;
if (!uniforms[E.value].subgroup.is_empty()) {
group += "::" + uniforms[E.value].subgroup;
}
if (group != last_group) {
PropertyInfo pi;
pi.usage = PROPERTY_USAGE_GROUP;
pi.name = group;
p_param_list->push_back(pi);
last_group = group;
}
PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
pi.name = E.value;
p_param_list->push_back(pi);

View file

@ -178,8 +178,22 @@ void SkyRD::SkyShaderData::get_param_list(List<PropertyInfo> *p_param_list) cons
order[E.value.order] = E.key;
}
}
String last_group;
for (const KeyValue<int, StringName> &E : order) {
String group = uniforms[E.value].group;
if (!uniforms[E.value].subgroup.is_empty()) {
group += "::" + uniforms[E.value].subgroup;
}
if (group != last_group) {
PropertyInfo pi;
pi.usage = PROPERTY_USAGE_GROUP;
pi.name = group;
p_param_list->push_back(pi);
last_group = group;
}
PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
pi.name = E.value;
p_param_list->push_back(pi);

View file

@ -407,7 +407,22 @@ void SceneShaderForwardClustered::ShaderData::get_param_list(List<PropertyInfo>
}
}
String last_group;
for (const KeyValue<int, StringName> &E : order) {
String group = uniforms[E.value].group;
if (!uniforms[E.value].subgroup.is_empty()) {
group += "::" + uniforms[E.value].subgroup;
}
if (group != last_group) {
PropertyInfo pi;
pi.usage = PROPERTY_USAGE_GROUP;
pi.name = group;
p_param_list->push_back(pi);
last_group = group;
}
PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
pi.name = E.value;
p_param_list->push_back(pi);

View file

@ -364,7 +364,22 @@ void SceneShaderForwardMobile::ShaderData::get_param_list(List<PropertyInfo> *p_
}
}
String last_group;
for (const KeyValue<int, StringName> &E : order) {
String group = uniforms[E.value].group;
if (!uniforms[E.value].subgroup.is_empty()) {
group += "::" + uniforms[E.value].subgroup;
}
if (group != last_group) {
PropertyInfo pi;
pi.usage = PROPERTY_USAGE_GROUP;
pi.name = group;
p_param_list->push_back(pi);
last_group = group;
}
PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
pi.name = E.value;
p_param_list->push_back(pi);

View file

@ -2185,7 +2185,22 @@ void RendererCanvasRenderRD::CanvasShaderData::get_param_list(List<PropertyInfo>
}
}
String last_group;
for (const KeyValue<int, StringName> &E : order) {
String group = uniforms[E.value].group;
if (!uniforms[E.value].subgroup.is_empty()) {
group += "::" + uniforms[E.value].subgroup;
}
if (group != last_group) {
PropertyInfo pi;
pi.usage = PROPERTY_USAGE_GROUP;
pi.name = group;
p_param_list->push_back(pi);
last_group = group;
}
PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
pi.name = E.value;
p_param_list->push_back(pi);

View file

@ -1612,7 +1612,22 @@ void ParticlesStorage::ParticlesShaderData::get_param_list(List<PropertyInfo> *p
}
}
String last_group;
for (const KeyValue<int, StringName> &E : order) {
String group = uniforms[E.value].group;
if (!uniforms[E.value].subgroup.is_empty()) {
group += "::" + uniforms[E.value].subgroup;
}
if (group != last_group) {
PropertyInfo pi;
pi.usage = PROPERTY_USAGE_GROUP;
pi.name = group;
p_param_list->push_back(pi);
last_group = group;
}
PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
pi.name = E.value;
p_param_list->push_back(pi);

View file

@ -310,6 +310,7 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = {
// global space keywords
{ TK_UNIFORM, "uniform", CF_GLOBAL_SPACE | CF_UNIFORM_KEYWORD, {}, {} },
{ TK_UNIFORM_GROUP, "group_uniforms", CF_GLOBAL_SPACE, {}, {} },
{ TK_VARYING, "varying", CF_GLOBAL_SPACE, { "particles", "sky", "fog" }, {} },
{ TK_CONST, "const", CF_BLOCK | CF_GLOBAL_SPACE | CF_CONST_KEYWORD, {}, {} },
{ TK_STRUCT, "struct", CF_GLOBAL_SPACE, {}, {} },
@ -1146,6 +1147,8 @@ void ShaderLanguage::clear() {
current_function = StringName();
last_name = StringName();
last_type = IDENTIFIER_MAX;
current_uniform_group_name = "";
current_uniform_subgroup_name = "";
completion_type = COMPLETION_NONE;
completion_block = nullptr;
@ -8298,6 +8301,8 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
uniform.scope = uniform_scope;
uniform.precision = precision;
uniform.array_size = array_size;
uniform.group = current_uniform_group_name;
uniform.subgroup = current_uniform_subgroup_name;
tk = _get_token();
if (tk.type == TK_BRACKET_OPEN) {
@ -8724,6 +8729,45 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
}
} break;
case TK_UNIFORM_GROUP: {
tk = _get_token();
if (tk.type == TK_IDENTIFIER) {
current_uniform_group_name = tk.text;
tk = _get_token();
if (tk.type == TK_PERIOD) {
tk = _get_token();
if (tk.type == TK_IDENTIFIER) {
current_uniform_subgroup_name = tk.text;
tk = _get_token();
if (tk.type != TK_SEMICOLON) {
_set_expected_error(";");
return ERR_PARSE_ERROR;
}
} else {
_set_error(RTR("Expected an uniform subgroup identifier."));
return ERR_PARSE_ERROR;
}
} else if (tk.type != TK_SEMICOLON) {
_set_expected_error(";", ".");
return ERR_PARSE_ERROR;
}
} else {
if (tk.type != TK_SEMICOLON) {
if (current_uniform_group_name.is_empty()) {
_set_error(RTR("Expected an uniform group identifier."));
} else {
_set_error(RTR("Expected an uniform group identifier or `;`."));
}
return ERR_PARSE_ERROR;
} else if (tk.type == TK_SEMICOLON && current_uniform_group_name.is_empty()) {
_set_error(RTR("Group needs to be opened before."));
return ERR_PARSE_ERROR;
} else {
current_uniform_group_name = "";
current_uniform_subgroup_name = "";
}
}
} break;
case TK_SHADER_TYPE: {
_set_error(RTR("Shader type is already defined."));
return ERR_PARSE_ERROR;

View file

@ -154,6 +154,7 @@ public:
TK_SEMICOLON,
TK_PERIOD,
TK_UNIFORM,
TK_UNIFORM_GROUP,
TK_INSTANCE,
TK_GLOBAL,
TK_VARYING,
@ -687,6 +688,8 @@ public:
TextureRepeat repeat = REPEAT_DEFAULT;
float hint_range[3];
int instance_index = 0;
String group;
String subgroup;
Uniform() {
hint_range[0] = 0.0f;
@ -938,6 +941,9 @@ private:
StringName last_name;
bool is_shader_inc = false;
String current_uniform_group_name;
String current_uniform_subgroup_name;
VaryingFunctionNames varying_function_names;
TkPos _get_tkpos() {