Browse Source

Fix shader crash when using boolean type for vertex->fragment varyings

Yuri Rubinsky 2 years ago
parent
commit
f28348fc5c

+ 5 - 0
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);

+ 33 - 2
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<StringName, FunctionInfo> &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<StringName, FunctionInfo> &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;

+ 2 - 0
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);