Browse Source

Merge pull request #60524 from Chaosus/fix_shader_precision

Yuri Rubinsky 3 years ago
parent
commit
a8abdc9372
2 changed files with 79 additions and 63 deletions
  1. 78 63
      servers/rendering/shader_language.cpp
  2. 1 0
      servers/rendering/shader_language.h

+ 78 - 63
servers/rendering/shader_language.cpp

@@ -4670,16 +4670,18 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
 				expr = _parse_array_constructor(p_block, p_function_info);
 			} else {
 				DataType datatype;
-				DataPrecision precision;
-				bool precision_defined = false;
+				DataPrecision precision = PRECISION_DEFAULT;
 
 				if (is_token_precision(tk.type)) {
 					precision = get_token_precision(tk.type);
-					precision_defined = true;
 					tk = _get_token();
 				}
 
 				datatype = get_token_datatype(tk.type);
+				if (precision != PRECISION_DEFAULT && _validate_precision(datatype, precision) != OK) {
+					return nullptr;
+				}
+
 				tk = _get_token();
 
 				if (tk.type == TK_BRACKET_OPEN) {
@@ -4697,7 +4699,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
 					OperatorNode *func = alloc_node<OperatorNode>();
 					func->op = OP_CONSTRUCT;
 
-					if (precision_defined) {
+					if (precision != PRECISION_DEFAULT) {
 						func->return_precision_cache = precision;
 					}
 
@@ -6426,10 +6428,6 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
 				if (!is_struct) {
 					is_struct = shader->structs.has(tk.text); // check again.
 				}
-				if (is_struct && precision != PRECISION_DEFAULT) {
-					_set_error(RTR("The precision modifier cannot be used on structs."));
-					return ERR_PARSE_ERROR;
-				}
 				if (!is_token_nonvoid_datatype(tk.type)) {
 					_set_error(RTR("Expected variable type after precision modifier."));
 					return ERR_PARSE_ERROR;
@@ -6449,6 +6447,10 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
 				return ERR_PARSE_ERROR;
 			}
 
+			if (precision != PRECISION_DEFAULT && _validate_precision(type, precision) != OK) {
+				return ERR_PARSE_ERROR;
+			}
+
 			int array_size = 0;
 			bool fixed_array_size = false;
 			bool first = true;
@@ -6600,10 +6602,6 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
 								if (is_token_precision(tk.type)) {
 									precision2 = get_token_precision(tk.type);
 									tk = _get_token();
-									if (shader->structs.has(tk.text)) {
-										_set_error(RTR("The precision modifier cannot be used on structs."));
-										return ERR_PARSE_ERROR;
-									}
 									if (!is_token_nonvoid_datatype(tk.type)) {
 										_set_error(RTR("Expected data type after precision modifier."));
 										return ERR_PARSE_ERROR;
@@ -6624,6 +6622,10 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
 									type2 = get_token_datatype(tk.type);
 								}
 
+								if (precision2 != PRECISION_DEFAULT && _validate_precision(type2, precision2) != OK) {
+									return ERR_PARSE_ERROR;
+								}
+
 								int array_size2 = 0;
 
 								tk = _get_token();
@@ -7427,6 +7429,25 @@ String ShaderLanguage::_get_qualifier_str(ArgumentQualifier p_qualifier) const {
 	return "";
 }
 
+Error ShaderLanguage::_validate_precision(DataType p_type, DataPrecision p_precision) {
+	switch (p_type) {
+		case TYPE_STRUCT: {
+			_set_error(RTR("The precision modifier cannot be used on structs."));
+			return FAILED;
+		} break;
+		case TYPE_BOOL:
+		case TYPE_BVEC2:
+		case TYPE_BVEC3:
+		case TYPE_BVEC4: {
+			_set_error(RTR("The precision modifier cannot be used on boolean types."));
+			return FAILED;
+		} break;
+		default:
+			break;
+	}
+	return OK;
+}
+
 Error ShaderLanguage::_validate_datatype(DataType p_type) {
 	if (RenderingServer::get_singleton()->is_low_end()) {
 		bool invalid_type = false;
@@ -7608,8 +7629,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
 					}
 					StringName struct_name = "";
 					bool struct_dt = false;
-					bool use_precision = false;
-					DataPrecision precision = DataPrecision::PRECISION_DEFAULT;
+					DataPrecision precision = PRECISION_DEFAULT;
 
 					if (tk.type == TK_STRUCT) {
 						_set_error(RTR("Nested structs are not allowed."));
@@ -7618,7 +7638,6 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
 
 					if (is_token_precision(tk.type)) {
 						precision = get_token_precision(tk.type);
-						use_precision = true;
 						tk = _get_token();
 					}
 
@@ -7630,10 +7649,6 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
 						}
 #endif // DEBUG_ENABLED
 						struct_dt = true;
-						if (use_precision) {
-							_set_error(RTR("The precision modifier cannot be used on structs."));
-							return ERR_PARSE_ERROR;
-						}
 					}
 
 					if (!is_token_datatype(tk.type) && !struct_dt) {
@@ -7642,6 +7657,10 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
 					} else {
 						type = struct_dt ? TYPE_STRUCT : get_token_datatype(tk.type);
 
+						if (precision != PRECISION_DEFAULT && _validate_precision(type, precision) != OK) {
+							return ERR_PARSE_ERROR;
+						}
+
 						if (type == TYPE_VOID || is_sampler_type(type)) {
 							_set_error(vformat(RTR("A '%s' data type is not allowed here."), get_datatype_name(type)));
 							return ERR_PARSE_ERROR;
@@ -7762,7 +7781,6 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
 					}
 				}
 
-				bool precision_defined = false;
 				DataPrecision precision = PRECISION_DEFAULT;
 				DataInterpolation interpolation = INTERPOLATION_SMOOTH;
 				DataType type;
@@ -7781,16 +7799,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
 
 				if (is_token_precision(tk.type)) {
 					precision = get_token_precision(tk.type);
-					precision_defined = true;
 					tk = _get_token();
 				}
 
 				if (shader->structs.has(tk.text)) {
 					if (uniform) {
-						if (precision_defined) {
-							_set_error(RTR("The precision modifier cannot be used on structs."));
-							return ERR_PARSE_ERROR;
-						}
 						_set_error(vformat(RTR("The '%s' data type is not supported for uniforms."), "struct"));
 						return ERR_PARSE_ERROR;
 					} else {
@@ -7806,6 +7819,10 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
 
 				type = get_token_datatype(tk.type);
 
+				if (precision != PRECISION_DEFAULT && _validate_precision(type, precision) != OK) {
+					return ERR_PARSE_ERROR;
+				}
+
 				if (type == TYPE_VOID) {
 					_set_error(vformat(RTR("The '%s' data type is not allowed here."), "void"));
 					return ERR_PARSE_ERROR;
@@ -8249,10 +8266,6 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
 				}
 
 				if (shader->structs.has(tk.text)) {
-					if (precision != PRECISION_DEFAULT) {
-						_set_error(RTR("The precision modifier cannot be used on structs."));
-						return ERR_PARSE_ERROR;
-					}
 					is_struct = true;
 					struct_name = tk.text;
 				} else {
@@ -8276,6 +8289,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
 				} else {
 					type = get_token_datatype(tk.type);
 				}
+
+				if (precision != PRECISION_DEFAULT && _validate_precision(type, precision) != OK) {
+					return ERR_PARSE_ERROR;
+				}
+
 				prev_pos = _get_tkpos();
 				tk = _get_token();
 
@@ -8652,44 +8670,41 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
 						break;
 					}
 
-					bool is_const = false;
+					bool param_is_const = false;
 					if (tk.type == TK_CONST) {
-						is_const = true;
+						param_is_const = true;
 						tk = _get_token();
 					}
 
-					ArgumentQualifier qualifier = ARGUMENT_QUALIFIER_IN;
-
+					ArgumentQualifier param_qualifier = ARGUMENT_QUALIFIER_IN;
 					if (tk.type == TK_ARG_IN) {
-						qualifier = ARGUMENT_QUALIFIER_IN;
+						param_qualifier = ARGUMENT_QUALIFIER_IN;
 						tk = _get_token();
 					} else if (tk.type == TK_ARG_OUT) {
-						if (is_const) {
+						if (param_is_const) {
 							_set_error(vformat(RTR("The '%s' qualifier cannot be used within a function parameter declared with '%s'."), "out", "const"));
 							return ERR_PARSE_ERROR;
 						}
-						qualifier = ARGUMENT_QUALIFIER_OUT;
+						param_qualifier = ARGUMENT_QUALIFIER_OUT;
 						tk = _get_token();
 					} else if (tk.type == TK_ARG_INOUT) {
-						if (is_const) {
+						if (param_is_const) {
 							_set_error(vformat(RTR("The '%s' qualifier cannot be used within a function parameter declared with '%s'."), "inout", "const"));
 							return ERR_PARSE_ERROR;
 						}
-						qualifier = ARGUMENT_QUALIFIER_INOUT;
+						param_qualifier = ARGUMENT_QUALIFIER_INOUT;
 						tk = _get_token();
 					}
 
-					DataType ptype;
-					StringName pname;
+					DataType param_type;
+					StringName param_name;
 					StringName param_struct_name;
-					DataPrecision pprecision = PRECISION_DEFAULT;
-					bool use_precision = false;
+					DataPrecision param_precision = PRECISION_DEFAULT;
 					int arg_array_size = 0;
 
 					if (is_token_precision(tk.type)) {
-						pprecision = get_token_precision(tk.type);
+						param_precision = get_token_precision(tk.type);
 						tk = _get_token();
-						use_precision = true;
 					}
 
 					is_struct = false;
@@ -8702,10 +8717,6 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
 							used_structs[param_struct_name].used = true;
 						}
 #endif // DEBUG_ENABLED
-						if (use_precision) {
-							_set_error(RTR("The precision modifier cannot be used on structs."));
-							return ERR_PARSE_ERROR;
-						}
 					}
 
 					if (!is_struct && !is_token_datatype(tk.type)) {
@@ -8713,7 +8724,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
 						return ERR_PARSE_ERROR;
 					}
 
-					if (qualifier == ARGUMENT_QUALIFIER_OUT || qualifier == ARGUMENT_QUALIFIER_INOUT) {
+					if (param_qualifier == ARGUMENT_QUALIFIER_OUT || param_qualifier == ARGUMENT_QUALIFIER_INOUT) {
 						if (is_sampler_type(get_token_datatype(tk.type))) {
 							_set_error(RTR("Opaque types cannot be output parameters."));
 							return ERR_PARSE_ERROR;
@@ -8721,18 +8732,22 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
 					}
 
 					if (is_struct) {
-						ptype = TYPE_STRUCT;
+						param_type = TYPE_STRUCT;
 					} else {
-						ptype = get_token_datatype(tk.type);
-						if (_validate_datatype(ptype) != OK) {
+						param_type = get_token_datatype(tk.type);
+						if (_validate_datatype(param_type) != OK) {
 							return ERR_PARSE_ERROR;
 						}
-						if (ptype == TYPE_VOID) {
+						if (param_type == TYPE_VOID) {
 							_set_error(RTR("Void type not allowed as argument."));
 							return ERR_PARSE_ERROR;
 						}
 					}
 
+					if (param_precision != PRECISION_DEFAULT && _validate_precision(param_type, param_precision) != OK) {
+						return ERR_PARSE_ERROR;
+					}
+
 					tk = _get_token();
 
 					if (tk.type == TK_BRACKET_OPEN) {
@@ -8747,32 +8762,32 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
 						return ERR_PARSE_ERROR;
 					}
 
-					pname = tk.text;
+					param_name = tk.text;
 
 					ShaderLanguage::IdentifierType itype;
-					if (_find_identifier(func_node->body, false, builtins, pname, (ShaderLanguage::DataType *)nullptr, &itype)) {
+					if (_find_identifier(func_node->body, false, builtins, param_name, (ShaderLanguage::DataType *)nullptr, &itype)) {
 						if (itype != IDENTIFIER_FUNCTION) {
-							_set_redefinition_error(String(pname));
+							_set_redefinition_error(String(param_name));
 							return ERR_PARSE_ERROR;
 						}
 					}
 
-					if (has_builtin(p_functions, pname)) {
-						_set_redefinition_error(String(pname));
+					if (has_builtin(p_functions, param_name)) {
+						_set_redefinition_error(String(param_name));
 						return ERR_PARSE_ERROR;
 					}
 
 					FunctionNode::Argument arg;
-					arg.type = ptype;
-					arg.name = pname;
+					arg.type = param_type;
+					arg.name = param_name;
 					arg.type_str = param_struct_name;
-					arg.precision = pprecision;
-					arg.qualifier = qualifier;
+					arg.precision = param_precision;
+					arg.qualifier = param_qualifier;
 					arg.tex_argument_check = false;
 					arg.tex_builtin_check = false;
 					arg.tex_argument_filter = FILTER_DEFAULT;
 					arg.tex_argument_repeat = REPEAT_DEFAULT;
-					arg.is_const = is_const;
+					arg.is_const = param_is_const;
 
 					tk = _get_token();
 					if (tk.type == TK_BRACKET_OPEN) {

+ 1 - 0
servers/rendering/shader_language.h

@@ -1038,6 +1038,7 @@ private:
 
 	static bool is_const_suffix_lut_initialized;
 
+	Error _validate_precision(DataType p_type, DataPrecision p_precision);
 	Error _validate_datatype(DataType p_type);
 	bool _compare_datatypes(DataType p_datatype_a, String p_datatype_name_a, int p_array_size_a, DataType p_datatype_b, String p_datatype_name_b, int p_array_size_b);
 	bool _compare_datatypes_in_nodes(Node *a, Node *b);