mirror of
				https://github.com/godotengine/godot.git
				synced 2025-10-31 13:41:03 +00:00 
			
		
		
		
	Allow pass varyings as out param to the function, when it's possible
This commit is contained in:
		
							parent
							
								
									1906b59675
								
							
						
					
					
						commit
						108b6a2000
					
				
					 2 changed files with 92 additions and 87 deletions
				
			
		|  | @ -977,8 +977,6 @@ void ShaderLanguage::clear() { | |||
| 	completion_base = TYPE_VOID; | ||||
| 	completion_base_array = false; | ||||
| 
 | ||||
| 	unknown_varying_usages.clear(); | ||||
| 
 | ||||
| #ifdef DEBUG_ENABLED | ||||
| 	used_constants.clear(); | ||||
| 	used_varyings.clear(); | ||||
|  | @ -4122,43 +4120,6 @@ bool ShaderLanguage::_validate_varying_assign(ShaderNode::Varying &p_varying, St | |||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| bool ShaderLanguage::_validate_varying_using(ShaderNode::Varying &p_varying, String *r_message) { | ||||
| 	switch (p_varying.stage) { | ||||
| 		case ShaderNode::Varying::STAGE_UNKNOWN: | ||||
| 			VaryingUsage usage; | ||||
| 			usage.var = &p_varying; | ||||
| 			usage.line = tk_line; | ||||
| 			unknown_varying_usages.push_back(usage); | ||||
| 			break; | ||||
| 		case ShaderNode::Varying::STAGE_VERTEX: | ||||
| 			if (current_function == varying_function_names.fragment || current_function == varying_function_names.light) { | ||||
| 				p_varying.stage = ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT_LIGHT; | ||||
| 			} | ||||
| 			break; | ||||
| 		case ShaderNode::Varying::STAGE_FRAGMENT: | ||||
| 			if (current_function == varying_function_names.light) { | ||||
| 				p_varying.stage = ShaderNode::Varying::STAGE_FRAGMENT_TO_LIGHT; | ||||
| 			} | ||||
| 			break; | ||||
| 		default: | ||||
| 			break; | ||||
| 	} | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| bool ShaderLanguage::_check_varying_usages(int *r_error_line, String *r_error_message) const { | ||||
| 	for (const List<ShaderLanguage::VaryingUsage>::Element *E = unknown_varying_usages.front(); E; E = E->next()) { | ||||
| 		ShaderNode::Varying::Stage stage = E->get().var->stage; | ||||
| 		if (stage != ShaderNode::Varying::STAGE_UNKNOWN && stage != ShaderNode::Varying::STAGE_VERTEX && stage != ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT_LIGHT) { | ||||
| 			*r_error_line = E->get().line; | ||||
| 			*r_error_message = RTR("Fragment-stage varying could not been accessed in custom function!"); | ||||
| 			return false; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| bool ShaderLanguage::_check_node_constness(const Node *p_node) const { | ||||
| 	switch (p_node->type) { | ||||
| 		case Node::TYPE_OPERATOR: { | ||||
|  | @ -4991,55 +4952,104 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons | |||
| 							for (int i = 0; i < call_function->arguments.size(); i++) { | ||||
| 								int argidx = i + 1; | ||||
| 								if (argidx < func->arguments.size()) { | ||||
| 									if (call_function->arguments[i].is_const || call_function->arguments[i].qualifier == ArgumentQualifier::ARGUMENT_QUALIFIER_OUT || call_function->arguments[i].qualifier == ArgumentQualifier::ARGUMENT_QUALIFIER_INOUT) { | ||||
| 									bool error = false; | ||||
| 									Node *n = func->arguments[argidx]; | ||||
| 										if (n->type == Node::TYPE_CONSTANT || n->type == Node::TYPE_OPERATOR) { | ||||
| 											if (!call_function->arguments[i].is_const) { | ||||
| 									ArgumentQualifier arg_qual = call_function->arguments[i].qualifier; | ||||
| 									bool is_out_arg = arg_qual != ArgumentQualifier::ARGUMENT_QUALIFIER_IN; | ||||
| 
 | ||||
| 									if (n->type == Node::TYPE_VARIABLE || n->type == Node::TYPE_ARRAY) { | ||||
| 										StringName varname; | ||||
| 
 | ||||
| 										if (n->type == Node::TYPE_VARIABLE) { | ||||
| 											VariableNode *vn = static_cast<VariableNode *>(n); | ||||
| 											varname = vn->name; | ||||
| 										} else { // TYPE_ARRAY
 | ||||
| 											ArrayNode *an = static_cast<ArrayNode *>(n); | ||||
| 											varname = an->name; | ||||
| 										} | ||||
| 
 | ||||
| 										if (shader->varyings.has(varname)) { | ||||
| 											switch (shader->varyings[varname].stage) { | ||||
| 												case ShaderNode::Varying::STAGE_UNKNOWN: { | ||||
| 													_set_error(vformat("Varying '%s' must be assigned in the vertex or fragment function first!", varname)); | ||||
| 													return nullptr; | ||||
| 												} | ||||
| 												case ShaderNode::Varying::STAGE_VERTEX_TO_FRAGMENT_LIGHT: | ||||
| 													[[fallthrough]]; | ||||
| 												case ShaderNode::Varying::STAGE_VERTEX: | ||||
| 													if (is_out_arg && current_function != varying_function_names.vertex) { // inout/out
 | ||||
| 														error = true; | ||||
| 													} | ||||
| 													break; | ||||
| 												case ShaderNode::Varying::STAGE_FRAGMENT_TO_LIGHT: | ||||
| 													[[fallthrough]]; | ||||
| 												case ShaderNode::Varying::STAGE_FRAGMENT: | ||||
| 													if (!is_out_arg) { | ||||
| 														if (current_function != varying_function_names.fragment && current_function != varying_function_names.light) { | ||||
| 															error = true; | ||||
| 														} | ||||
| 													} else if (current_function != varying_function_names.fragment) { // inout/out
 | ||||
| 														error = true; | ||||
| 													} | ||||
| 													break; | ||||
| 												default: | ||||
| 													break; | ||||
| 											} | ||||
| 
 | ||||
| 											if (error) { | ||||
| 												_set_error(vformat("Varying '%s' cannot be passed for the '%s' parameter in that context!", varname, _get_qualifier_str(arg_qual))); | ||||
| 												return nullptr; | ||||
| 											} | ||||
| 										} | ||||
| 									} | ||||
| 
 | ||||
| 									bool is_const_arg = call_function->arguments[i].is_const; | ||||
| 
 | ||||
| 									if (is_const_arg || is_out_arg) { | ||||
| 										StringName varname; | ||||
| 
 | ||||
| 										if (n->type == Node::TYPE_CONSTANT || n->type == Node::TYPE_OPERATOR || n->type == Node::TYPE_ARRAY_CONSTRUCT) { | ||||
| 											if (!is_const_arg) { | ||||
| 												error = true; | ||||
| 											} | ||||
| 										} else if (n->type == Node::TYPE_ARRAY) { | ||||
| 											ArrayNode *an = static_cast<ArrayNode *>(n); | ||||
| 											if (an->call_expression != nullptr || an->is_const) { | ||||
| 											if (!is_const_arg && (an->call_expression != nullptr || an->is_const)) { | ||||
| 												error = true; | ||||
| 											} | ||||
| 											varname = an->name; | ||||
| 										} else if (n->type == Node::TYPE_VARIABLE) { | ||||
| 											VariableNode *vn = static_cast<VariableNode *>(n); | ||||
| 											if (vn->is_const) { | ||||
| 											if (vn->is_const && !is_const_arg) { | ||||
| 												error = true; | ||||
| 											} else { | ||||
| 												StringName varname = vn->name; | ||||
| 											} | ||||
| 											varname = vn->name; | ||||
| 										} else if (n->type == Node::TYPE_MEMBER) { | ||||
| 											MemberNode *mn = static_cast<MemberNode *>(n); | ||||
| 											if (mn->basetype_const && is_out_arg) { | ||||
| 												error = true; | ||||
| 											} | ||||
| 										} | ||||
| 										if (!error && varname != StringName()) { | ||||
| 											if (shader->constants.has(varname)) { | ||||
| 												error = true; | ||||
| 											} else if (shader->uniforms.has(varname)) { | ||||
| 												error = true; | ||||
| 												} else { | ||||
| 													if (shader->varyings.has(varname)) { | ||||
| 														_set_error(vformat("Varyings cannot be passed for '%s' parameter!", _get_qualifier_str(call_function->arguments[i].qualifier))); | ||||
| 														return nullptr; | ||||
| 													} | ||||
| 													if (p_function_info.built_ins.has(varname)) { | ||||
| 											} else if (p_function_info.built_ins.has(varname)) { | ||||
| 												BuiltInInfo info = p_function_info.built_ins[varname]; | ||||
| 												if (info.constant) { | ||||
| 													error = true; | ||||
| 												} | ||||
| 											} | ||||
| 										} | ||||
| 											} | ||||
| 										} else if (n->type == Node::TYPE_MEMBER) { | ||||
| 											MemberNode *mn = static_cast<MemberNode *>(n); | ||||
| 											if (mn->basetype_const) { | ||||
| 												error = true; | ||||
| 											} | ||||
| 										} | ||||
| 
 | ||||
| 										if (error) { | ||||
| 											_set_error(vformat("Constant value cannot be passed for '%s' parameter!", _get_qualifier_str(call_function->arguments[i].qualifier))); | ||||
| 											_set_error(vformat("Constant value cannot be passed for '%s' parameter!", _get_qualifier_str(arg_qual))); | ||||
| 											return nullptr; | ||||
| 										} | ||||
| 									} | ||||
| 									if (is_sampler_type(call_function->arguments[i].type)) { | ||||
| 										//let's see where our argument comes from
 | ||||
| 										Node *n = func->arguments[argidx]; | ||||
| 										ERR_CONTINUE(n->type != Node::TYPE_VARIABLE); //bug? this should always be a variable
 | ||||
| 										VariableNode *vn = static_cast<VariableNode *>(n); | ||||
| 										StringName varname = vn->name; | ||||
|  | @ -5143,9 +5153,21 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons | |||
| 								return nullptr; | ||||
| 							} | ||||
| 						} else { | ||||
| 							if (!_validate_varying_using(shader->varyings[identifier], &error)) { | ||||
| 								_set_error(error); | ||||
| 								return nullptr; | ||||
| 							ShaderNode::Varying &var = shader->varyings[identifier]; | ||||
| 
 | ||||
| 							switch (var.stage) { | ||||
| 								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; | ||||
| 									} | ||||
| 									break; | ||||
| 								case ShaderNode::Varying::STAGE_FRAGMENT: | ||||
| 									if (current_function == varying_function_names.light) { | ||||
| 										var.stage = ShaderNode::Varying::STAGE_FRAGMENT_TO_LIGHT; | ||||
| 									} | ||||
| 									break; | ||||
| 								default: | ||||
| 									break; | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
|  | @ -8958,14 +8980,6 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct | |||
| 		tk = _get_token(); | ||||
| 	} | ||||
| 
 | ||||
| 	int error_line; | ||||
| 	String error_message; | ||||
| 	if (!_check_varying_usages(&error_line, &error_message)) { | ||||
| 		_set_tkpos({ 0, error_line }); | ||||
| 		_set_error(error_message); | ||||
| 		return ERR_PARSE_ERROR; | ||||
| 	} | ||||
| 
 | ||||
| 	return OK; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -938,14 +938,6 @@ private: | |||
| 
 | ||||
| 	VaryingFunctionNames varying_function_names; | ||||
| 
 | ||||
| 	struct VaryingUsage { | ||||
| 		ShaderNode::Varying *var; | ||||
| 		int line; | ||||
| 	}; | ||||
| 	List<VaryingUsage> unknown_varying_usages; | ||||
| 
 | ||||
| 	bool _check_varying_usages(int *r_error_line, String *r_error_message) const; | ||||
| 
 | ||||
| 	TkPos _get_tkpos() { | ||||
| 		TkPos tkp; | ||||
| 		tkp.char_idx = char_idx; | ||||
|  | @ -1047,7 +1039,6 @@ private: | |||
| 	bool _propagate_function_call_sampler_uniform_settings(StringName p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat); | ||||
| 	bool _propagate_function_call_sampler_builtin_reference(StringName p_name, int p_argument, const StringName &p_builtin); | ||||
| 	bool _validate_varying_assign(ShaderNode::Varying &p_varying, String *r_message); | ||||
| 	bool _validate_varying_using(ShaderNode::Varying &p_varying, String *r_message); | ||||
| 	bool _check_node_constness(const Node *p_node) const; | ||||
| 
 | ||||
| 	Node *_parse_array_size(BlockNode *p_block, const FunctionInfo &p_function_info, int &r_array_size); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Yuri Roubinsky
						Yuri Roubinsky