Refactor render_mode in shaders, forbid declaring duplicates

This commit is contained in:
Yuri Roubinsky 2021-12-21 17:21:55 +03:00
parent d3d6208ec8
commit e8a457ba89
8 changed files with 205 additions and 136 deletions

View File

@ -138,8 +138,18 @@ void ShaderTextEditor::_load_theme_settings() {
}
}
for (int i = 0; i < ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode())).size(); i++) {
built_ins.push_back(ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode()))[i]);
const Vector<ShaderLanguage::ModeInfo> &modes = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode()));
for (int i = 0; i < modes.size(); i++) {
const ShaderLanguage::ModeInfo &info = modes[i];
if (!info.options.is_empty()) {
for (int j = 0; j < info.options.size(); j++) {
built_ins.push_back(String(info.name) + "_" + String(info.options[j]));
}
} else {
built_ins.push_back(String(info.name));
}
}
}

View File

@ -1085,16 +1085,6 @@ String VisualShader::validate_uniform_name(const String &p_name, const Ref<Visua
return name;
}
VisualShader::RenderModeEnums VisualShader::render_mode_enums[] = {
{ Shader::MODE_SPATIAL, "blend" },
{ Shader::MODE_SPATIAL, "depth_draw" },
{ Shader::MODE_SPATIAL, "cull" },
{ Shader::MODE_SPATIAL, "diffuse" },
{ Shader::MODE_SPATIAL, "specular" },
{ Shader::MODE_CANVAS_ITEM, "blend" },
{ Shader::MODE_CANVAS_ITEM, nullptr }
};
static const char *type_string[VisualShader::TYPE_MAX] = {
"vertex",
"fragment",
@ -1261,27 +1251,25 @@ void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
Map<String, String> blend_mode_enums;
Set<String> toggles;
for (int i = 0; i < ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader_mode)).size(); i++) {
String mode = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader_mode))[i];
int idx = 0;
bool in_enum = false;
while (render_mode_enums[idx].string) {
if (mode.begins_with(render_mode_enums[idx].string)) {
String begin = render_mode_enums[idx].string;
String option = mode.replace_first(begin + "_", "");
const Vector<ShaderLanguage::ModeInfo> &rmodes = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader_mode));
for (int i = 0; i < rmodes.size(); i++) {
const ShaderLanguage::ModeInfo &info = rmodes[i];
if (!info.options.is_empty()) {
const String begin = String(info.name);
for (int j = 0; j < info.options.size(); j++) {
const String option = String(info.options[j]);
if (!blend_mode_enums.has(begin)) {
blend_mode_enums[begin] = option;
} else {
blend_mode_enums[begin] += "," + option;
}
in_enum = true;
break;
}
idx++;
}
if (!in_enum) {
toggles.insert(mode);
} else {
toggles.insert(String(info.name));
}
}
@ -1653,40 +1641,32 @@ void VisualShader::_update_shader() const {
String render_mode;
{
//fill render mode enums
int idx = 0;
while (render_mode_enums[idx].string) {
if (shader_mode == render_mode_enums[idx].mode) {
if (modes.has(render_mode_enums[idx].string)) {
int which = modes[render_mode_enums[idx].string];
int count = 0;
for (int i = 0; i < ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader_mode)).size(); i++) {
String mode = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader_mode))[i];
if (mode.begins_with(render_mode_enums[idx].string)) {
if (count == which) {
if (!render_mode.is_empty()) {
render_mode += ", ";
}
render_mode += mode;
break;
}
count++;
}
const Vector<ShaderLanguage::ModeInfo> &rmodes = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader_mode));
Vector<String> flag_names;
// Add enum modes first.
for (int i = 0; i < rmodes.size(); i++) {
const ShaderLanguage::ModeInfo &info = rmodes[i];
const String temp = String(info.name);
if (!info.options.is_empty()) {
if (modes.has(temp) && modes[temp] < info.options.size()) {
if (!render_mode.is_empty()) {
render_mode += ", ";
}
render_mode += temp + "_" + info.options[modes[temp]];
}
} else if (flags.has(temp)) {
flag_names.push_back(temp);
}
idx++;
}
//fill render mode flags
for (int i = 0; i < ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader_mode)).size(); i++) {
String mode = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader_mode))[i];
if (flags.has(mode)) {
if (!render_mode.is_empty()) {
render_mode += ", ";
}
render_mode += mode;
// Add flags afterward.
for (int i = 0; i < flag_names.size(); i++) {
if (!render_mode.is_empty()) {
render_mode += ", ";
}
render_mode += flag_names[i];
}
}

View File

@ -102,8 +102,6 @@ private:
HashMap<String, int> modes;
Set<StringName> flags;
static RenderModeEnums render_mode_enums[];
mutable SafeFlag dirty;
void _queue_update();

View File

@ -7510,7 +7510,7 @@ Error ShaderLanguage::_validate_datatype(DataType p_type) {
return OK;
}
Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const Set<String> &p_shader_types) {
Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_functions, const Vector<ModeInfo> &p_render_modes, const Set<String> &p_shader_types) {
Token tk = _get_token();
TkPos prev_pos;
@ -7554,6 +7554,8 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
stages = &p_functions;
const FunctionInfo &constants = p_functions.has("constants") ? p_functions["constants"] : FunctionInfo();
Map<String, String> defined_modes;
while (tk.type != TK_EOF) {
switch (tk.type) {
case TK_RENDER_MODE: {
@ -7566,13 +7568,40 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
return ERR_PARSE_ERROR;
}
if (p_render_modes.find(mode) == -1) {
_set_error("Invalid render mode: '" + String(mode) + "'");
const String smode = String(mode);
if (shader->render_modes.find(mode) != -1) {
_set_error(vformat("Duplicated render mode: '%s'.", smode));
return ERR_PARSE_ERROR;
}
if (shader->render_modes.find(mode) != -1) {
_set_error("Duplicate render mode: '" + String(mode) + "'");
bool found = false;
for (int i = 0; i < p_render_modes.size(); i++) {
const ModeInfo &info = p_render_modes[i];
const String name = String(info.name);
if (smode.begins_with(name)) {
if (!info.options.is_empty()) {
if (info.options.find(smode.substr(name.length() + 1)) != -1) {
found = true;
if (defined_modes.has(name)) {
_set_error(vformat("Redefinition of render mode: '%s'. The %s mode has already been set to '%s'.", smode, name, defined_modes[name]));
return ERR_PARSE_ERROR;
}
defined_modes.insert(name, smode);
break;
}
} else {
found = true;
break;
}
}
}
if (!found) {
_set_error(vformat("Invalid render mode: '%s'.", smode));
return ERR_PARSE_ERROR;
}
@ -9159,8 +9188,31 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
} break;
case COMPLETION_RENDER_MODE: {
for (int i = 0; i < p_info.render_modes.size(); i++) {
ScriptCodeCompletionOption option(p_info.render_modes[i], ScriptCodeCompletionOption::KIND_ENUM);
r_options->push_back(option);
const ModeInfo &info = p_info.render_modes[i];
if (!info.options.is_empty()) {
bool found = false;
for (int j = 0; j < info.options.size(); j++) {
if (shader->render_modes.has(String(info.name) + "_" + String(info.options[j]))) {
found = true;
}
}
if (!found) {
for (int j = 0; j < info.options.size(); j++) {
ScriptCodeCompletionOption option(String(info.name) + "_" + String(info.options[j]), ScriptCodeCompletionOption::KIND_ENUM);
r_options->push_back(option);
}
}
} else {
const String name = String(info.name);
if (!shader->render_modes.has(name)) {
ScriptCodeCompletionOption option(name, ScriptCodeCompletionOption::KIND_ENUM);
r_options->push_back(option);
}
}
}
return OK;

View File

@ -819,6 +819,57 @@ public:
DataType return_type = TYPE_VOID;
};
struct ModeInfo {
StringName name;
Vector<StringName> options;
ModeInfo() {}
ModeInfo(const StringName &p_name) :
name(p_name) {
}
ModeInfo(const StringName &p_name, const StringName &p_arg1, const StringName &p_arg2) :
name(p_name) {
options.push_back(p_arg1);
options.push_back(p_arg2);
}
ModeInfo(const StringName &p_name, const StringName &p_arg1, const StringName &p_arg2, const StringName &p_arg3) :
name(p_name) {
options.push_back(p_arg1);
options.push_back(p_arg2);
options.push_back(p_arg3);
}
ModeInfo(const StringName &p_name, const StringName &p_arg1, const StringName &p_arg2, const StringName &p_arg3, const StringName &p_arg4) :
name(p_name) {
options.push_back(p_arg1);
options.push_back(p_arg2);
options.push_back(p_arg3);
options.push_back(p_arg4);
}
ModeInfo(const StringName &p_name, const StringName &p_arg1, const StringName &p_arg2, const StringName &p_arg3, const StringName &p_arg4, const StringName &p_arg5) :
name(p_name) {
options.push_back(p_arg1);
options.push_back(p_arg2);
options.push_back(p_arg3);
options.push_back(p_arg4);
options.push_back(p_arg5);
}
ModeInfo(const StringName &p_name, const StringName &p_arg1, const StringName &p_arg2, const StringName &p_arg3, const StringName &p_arg4, const StringName &p_arg5, const StringName &p_arg6) :
name(p_name) {
options.push_back(p_arg1);
options.push_back(p_arg2);
options.push_back(p_arg3);
options.push_back(p_arg4);
options.push_back(p_arg5);
options.push_back(p_arg6);
}
};
struct FunctionInfo {
Map<StringName, BuiltInInfo> built_ins;
Map<StringName, StageFunctionInfo> stage_functions;
@ -1013,7 +1064,7 @@ private:
String _get_shader_type_list(const Set<String> &p_shader_types) const;
String _get_qualifier_str(ArgumentQualifier p_qualifier) const;
Error _parse_shader(const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const Set<String> &p_shader_types);
Error _parse_shader(const Map<StringName, FunctionInfo> &p_functions, const Vector<ModeInfo> &p_render_modes, const Set<String> &p_shader_types);
Error _find_last_flow_op_in_block(BlockNode *p_block, FlowOperation p_op);
Error _find_last_flow_op_in_op(ControlFlowNode *p_flow, FlowOperation p_op);
@ -1037,7 +1088,7 @@ public:
struct ShaderCompileInfo {
Map<StringName, FunctionInfo> functions;
Vector<StringName> render_modes;
Vector<ModeInfo> render_modes;
VaryingFunctionNames varying_function_names = VaryingFunctionNames();
Set<String> shader_types;
GlobalVariableGetTypeFunc global_variable_type_func = nullptr;

View File

@ -35,7 +35,7 @@ const Map<StringName, ShaderLanguage::FunctionInfo> &ShaderTypes::get_functions(
return shader_modes[p_mode].functions;
}
const Vector<StringName> &ShaderTypes::get_modes(RS::ShaderMode p_mode) const {
const Vector<ShaderLanguage::ModeInfo> &ShaderTypes::get_modes(RS::ShaderMode p_mode) const {
return shader_modes[p_mode].modes;
}
@ -190,53 +190,29 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SPATIAL].functions["light"].can_discard = true;
shader_modes[RS::SHADER_SPATIAL].functions["light"].main_function = true;
//order used puts first enum mode (default) first
shader_modes[RS::SHADER_SPATIAL].modes.push_back("blend_mix");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("blend_add");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("blend_sub");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("blend_mul");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("depth_draw_opaque");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("depth_draw_always");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("depth_draw_never");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("depth_prepass_alpha");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("depth_test_disabled");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("sss_mode_skin");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("cull_back");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("cull_front");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("cull_disabled");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("unshaded");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("wireframe");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("diffuse_lambert");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("diffuse_lambert_wrap");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("diffuse_burley");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("diffuse_toon");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("specular_schlick_ggx");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("specular_blinn");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("specular_phong");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("specular_toon");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("specular_disabled");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("skip_vertex_transform");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("world_vertex_coords");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("ensure_correct_normals");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("shadows_disabled");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("ambient_light_disabled");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("shadow_to_opacity");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("vertex_lighting");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("particle_trails");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("alpha_to_coverage");
shader_modes[RS::SHADER_SPATIAL].modes.push_back("alpha_to_coverage_and_one");
// spatial render modes
{
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "blend", "mix", "add", "sub", "mul" });
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "depth_draw", "opaque", "always", "never" });
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "depth_prepass_alpha" });
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "depth_test_disabled" });
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "sss_mode_skin" });
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "cull", "back", "front", "disabled" });
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "unshaded" });
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "wireframe" });
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "diffuse", "lambert", "lambert_wrap", "burley", "toon" });
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "specular", "schlick_ggx", "blinn", "phong", "toon", "disabled" });
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "skip_vertex_transform" });
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "world_vertex_coords" });
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "ensure_correct_normals" });
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "shadows_disabled" });
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "ambient_light_disabled" });
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "shadow_to_opacity" });
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "vertex_lighting" });
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "particle_trails" });
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "alpha_to_coverage" });
shader_modes[RS::SHADER_SPATIAL].modes.push_back({ "alpha_to_coverage_and_one" });
}
/************ CANVAS ITEM **************************/
@ -319,17 +295,13 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].can_discard = true;
shader_modes[RS::SHADER_CANVAS_ITEM].functions["light"].main_function = true;
shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back("skip_vertex_transform");
shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back("blend_mix");
shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back("blend_add");
shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back("blend_sub");
shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back("blend_mul");
shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back("blend_premul_alpha");
shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back("blend_disabled");
shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back("unshaded");
shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back("light_only");
// canvasitem render modes
{
shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back({ "skip_vertex_transform" });
shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back({ "blend", "mix", "add", "sub", "mul", "premul_alpha", "disabled" });
shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back({ "unshaded" });
shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back({ "light_only" });
}
/************ PARTICLES **************************/
@ -392,10 +364,13 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_PARTICLES].functions["process"].stage_functions["emit_subparticle"] = emit_vertex_func;
}
shader_modes[RS::SHADER_PARTICLES].modes.push_back("collision_use_scale");
shader_modes[RS::SHADER_PARTICLES].modes.push_back("disable_force");
shader_modes[RS::SHADER_PARTICLES].modes.push_back("disable_velocity");
shader_modes[RS::SHADER_PARTICLES].modes.push_back("keep_data");
// particles render modes
{
shader_modes[RS::SHADER_PARTICLES].modes.push_back({ "collision_use_scale" });
shader_modes[RS::SHADER_PARTICLES].modes.push_back({ "disable_force" });
shader_modes[RS::SHADER_PARTICLES].modes.push_back({ "disable_velocity" });
shader_modes[RS::SHADER_PARTICLES].modes.push_back({ "keep_data" });
}
/************ SKY **************************/
@ -439,9 +414,12 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SKY].functions["sky"].built_ins["FOG"] = ShaderLanguage::TYPE_VEC4;
shader_modes[RS::SHADER_SKY].functions["sky"].main_function = true;
shader_modes[RS::SHADER_SKY].modes.push_back("use_half_res_pass");
shader_modes[RS::SHADER_SKY].modes.push_back("use_quarter_res_pass");
shader_modes[RS::SHADER_SKY].modes.push_back("disable_fog");
// sky render modes
{
shader_modes[RS::SHADER_SKY].modes.push_back({ "use_half_res_pass" });
shader_modes[RS::SHADER_SKY].modes.push_back({ "use_quarter_res_pass" });
shader_modes[RS::SHADER_SKY].modes.push_back({ "disable_fog" });
}
/************ FOG **************************/

View File

@ -38,7 +38,7 @@
class ShaderTypes {
struct Type {
Map<StringName, ShaderLanguage::FunctionInfo> functions;
Vector<StringName> modes;
Vector<ShaderLanguage::ModeInfo> modes;
};
Map<RS::ShaderMode, Type> shader_modes;
@ -52,7 +52,7 @@ public:
static ShaderTypes *get_singleton() { return singleton; }
const Map<StringName, ShaderLanguage::FunctionInfo> &get_functions(RS::ShaderMode p_mode) const;
const Vector<StringName> &get_modes(RS::ShaderMode p_mode) const;
const Vector<ShaderLanguage::ModeInfo> &get_modes(RS::ShaderMode p_mode) const;
const Set<String> &get_types() const;
const List<String> &get_types_list() const;

View File

@ -341,8 +341,8 @@ MainLoop *test() {
dt["fragment"].built_ins["ALBEDO"] = SL::TYPE_VEC3;
dt["fragment"].can_discard = true;
Vector<StringName> rm;
rm.push_back("popo");
Vector<SL::ModeInfo> rm;
rm.push_back({ "popo" });
Set<String> types;
types.insert("spatial");