From f28348fc5c16cbcc6f1304b29c3f7e0a379391a3 Mon Sep 17 00:00:00 2001 From: Yuri Rubinsky Date: Thu, 22 Dec 2022 23:19:30 +0300 Subject: [PATCH] Fix shader crash when using boolean type for vertex->fragment varyings --- servers/rendering/shader_compiler.cpp | 5 ++++ servers/rendering/shader_language.cpp | 35 +++++++++++++++++++++++++-- servers/rendering/shader_language.h | 2 ++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/servers/rendering/shader_compiler.cpp b/servers/rendering/shader_compiler.cpp index 3604756fd8e..00b6a8c44ca 100644 --- a/servers/rendering/shader_compiler.cpp +++ b/servers/rendering/shader_compiler.cpp @@ -134,6 +134,8 @@ static String _interpstr(SL::DataInterpolation p_interp) { return "flat "; case SL::INTERPOLATION_SMOOTH: return ""; + case SL::INTERPOLATION_DEFAULT: + return ""; } return ""; } @@ -667,6 +669,9 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene fragment_varyings.insert(varying_name); continue; } + if (varying.type < SL::TYPE_INT) { + continue; // Ignore boolean types to prevent crashing (if varying is just declared). + } String vcode; String interp_mode = _interpstr(varying.interpolation); diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index 512995dd835..8c732b3d5af 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -989,6 +989,18 @@ String ShaderLanguage::get_precision_name(DataPrecision p_type) { return ""; } +String ShaderLanguage::get_interpolation_name(DataInterpolation p_interpolation) { + switch (p_interpolation) { + case INTERPOLATION_FLAT: + return "flat"; + case INTERPOLATION_SMOOTH: + return "smooth"; + default: + break; + } + return ""; +} + String ShaderLanguage::get_datatype_name(DataType p_type) { switch (p_type) { case TYPE_VOID: @@ -4424,6 +4436,10 @@ bool ShaderLanguage::_validate_varying_assign(ShaderNode::Varying &p_varying, St switch (p_varying.stage) { case ShaderNode::Varying::STAGE_UNKNOWN: // first assign if (current_function == varying_function_names.vertex) { + if (p_varying.type < TYPE_INT) { + *r_message = vformat(RTR("Varying with '%s' data type may only be assigned in the 'fragment' function."), get_datatype_name(p_varying.type)); + return false; + } p_varying.stage = ShaderNode::Varying::STAGE_VERTEX; } else if (current_function == varying_function_names.fragment) { p_varying.stage = ShaderNode::Varying::STAGE_FRAGMENT; @@ -5223,7 +5239,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons if (shader->varyings.has(varname)) { switch (shader->varyings[varname].stage) { case ShaderNode::Varying::STAGE_UNKNOWN: { - _set_error(vformat(RTR("Varying '%s' must be assigned in the vertex or fragment function first."), varname)); + _set_error(vformat(RTR("Varying '%s' must be assigned in the 'vertex' or 'fragment' function first."), varname)); return nullptr; } case ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT_LIGHT: @@ -5407,6 +5423,16 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } } else { switch (var.stage) { + case ShaderNode::Varying::STAGE_UNKNOWN: { + if (var.type < TYPE_INT) { + if (current_function == varying_function_names.vertex) { + _set_error(vformat(RTR("Varying with '%s' data type may only be used in the 'fragment' function."), get_datatype_name(var.type))); + } else { + _set_error(vformat(RTR("Varying '%s' must be assigned in the 'fragment' function first."), identifier)); + } + return nullptr; + } + } break; case ShaderNode::Varying::STAGE_VERTEX: if (current_function == varying_function_names.fragment || current_function == varying_function_names.light) { var.stage = ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT_LIGHT; @@ -8225,7 +8251,7 @@ Error ShaderLanguage::_parse_shader(const HashMap &p_f } } DataPrecision precision = PRECISION_DEFAULT; - DataInterpolation interpolation = INTERPOLATION_SMOOTH; + DataInterpolation interpolation = INTERPOLATION_DEFAULT; DataType type; StringName name; int array_size = 0; @@ -8334,6 +8360,11 @@ Error ShaderLanguage::_parse_shader(const HashMap &p_f return ERR_PARSE_ERROR; } + if (!is_uniform && interpolation != INTERPOLATION_DEFAULT && type < TYPE_INT) { + _set_error(vformat(RTR("Interpolation modifier '%s' cannot be used with boolean types."), get_interpolation_name(interpolation))); + return ERR_PARSE_ERROR; + } + if (!is_uniform && type > TYPE_MAT4) { _set_error(RTR("Invalid data type for varying.")); return ERR_PARSE_ERROR; diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h index 9c3cc9c5cd9..d34114589f5 100644 --- a/servers/rendering/shader_language.h +++ b/servers/rendering/shader_language.h @@ -247,6 +247,7 @@ public: enum DataInterpolation { INTERPOLATION_FLAT, INTERPOLATION_SMOOTH, + INTERPOLATION_DEFAULT, }; enum Operator { @@ -774,6 +775,7 @@ public: static bool is_token_arg_qual(TokenType p_type); static DataPrecision get_token_precision(TokenType p_type); static String get_precision_name(DataPrecision p_type); + static String get_interpolation_name(DataInterpolation p_interpolation); static String get_datatype_name(DataType p_type); static String get_uniform_hint_name(ShaderNode::Uniform::Hint p_hint); static String get_texture_filter_name(TextureFilter p_filter);