Browse Source

Add a shader warning when the uniform buffer limit is exceeded

Yuri Roubinsky 3 years ago
parent
commit
fd9c92d4ab

+ 9 - 4
editor/plugins/shader_editor_plugin.cpp

@@ -293,15 +293,20 @@ void ShaderTextEditor::_update_warning_panel() {
 		}
 		}
 
 
 		warning_count++;
 		warning_count++;
+		int line = w.get_line();
 
 
 		// First cell.
 		// First cell.
 		warnings_panel->push_cell();
 		warnings_panel->push_cell();
-		warnings_panel->push_meta(w.get_line() - 1);
 		warnings_panel->push_color(warnings_panel->get_theme_color(SNAME("warning_color"), SNAME("Editor")));
 		warnings_panel->push_color(warnings_panel->get_theme_color(SNAME("warning_color"), SNAME("Editor")));
-		warnings_panel->add_text(TTR("Line") + " " + itos(w.get_line()));
-		warnings_panel->add_text(" (" + w.get_name() + "):");
+		if (line != -1) {
+			warnings_panel->push_meta(line - 1);
+			warnings_panel->add_text(TTR("Line") + " " + itos(line));
+			warnings_panel->add_text(" (" + w.get_name() + "):");
+			warnings_panel->pop(); // Meta goto.
+		} else {
+			warnings_panel->add_text(w.get_name() + ":");
+		}
 		warnings_panel->pop(); // Color.
 		warnings_panel->pop(); // Color.
-		warnings_panel->pop(); // Meta goto.
 		warnings_panel->pop(); // Cell.
 		warnings_panel->pop(); // Cell.
 
 
 		// Second cell.
 		// Second cell.

+ 1 - 1
main/main.cpp

@@ -350,7 +350,7 @@ void Main::print_help(const char *p_binary) {
 	OS::get_singleton()->print("  -b, --breakpoints                            Breakpoint list as source::line comma-separated pairs, no spaces (use %%20 instead).\n");
 	OS::get_singleton()->print("  -b, --breakpoints                            Breakpoint list as source::line comma-separated pairs, no spaces (use %%20 instead).\n");
 	OS::get_singleton()->print("  --profiling                                  Enable profiling in the script debugger.\n");
 	OS::get_singleton()->print("  --profiling                                  Enable profiling in the script debugger.\n");
 	OS::get_singleton()->print("  --vk-layers                                  Enable Vulkan Validation layers for debugging.\n");
 	OS::get_singleton()->print("  --vk-layers                                  Enable Vulkan Validation layers for debugging.\n");
-#if DEBUG_ENABLED
+#ifdef DEBUG_ENABLED
 	OS::get_singleton()->print("  --gpu-abort                                  Abort on GPU errors (usually validation layer errors), may help see the problem if your system freezes.\n");
 	OS::get_singleton()->print("  --gpu-abort                                  Abort on GPU errors (usually validation layer errors), may help see the problem if your system freezes.\n");
 #endif
 #endif
 	OS::get_singleton()->print("  --remote-debug <uri>                         Remote debug (<protocol>://<host/IP>[:<port>], e.g. tcp://127.0.0.1:6007).\n");
 	OS::get_singleton()->print("  --remote-debug <uri>                         Remote debug (<protocol>://<host/IP>[:<port>], e.g. tcp://127.0.0.1:6007).\n");

+ 1 - 1
servers/audio_server.cpp

@@ -1591,7 +1591,7 @@ void AudioServer::set_bus_layout(const Ref<AudioBusLayout> &p_bus_layout) {
 				Bus::Effect bfx;
 				Bus::Effect bfx;
 				bfx.effect = fx;
 				bfx.effect = fx;
 				bfx.enabled = p_bus_layout->buses[i].effects[j].enabled;
 				bfx.enabled = p_bus_layout->buses[i].effects[j].enabled;
-#if DEBUG_ENABLED
+#ifdef DEBUG_ENABLED
 				bfx.prof_time = 0;
 				bfx.prof_time = 0;
 #endif
 #endif
 				bus->effects.push_back(bfx);
 				bus->effects.push_back(bfx);

+ 2 - 2
servers/rendering/renderer_rd/renderer_storage_rd.cpp

@@ -2655,13 +2655,13 @@ void RendererStorageRD::MaterialData::update_uniform_buffer(const Map<StringName
 		uint32_t size = 0U;
 		uint32_t size = 0U;
 		// The following code enforces a 16-byte alignment of uniform arrays.
 		// The following code enforces a 16-byte alignment of uniform arrays.
 		if (E.value.array_size > 0) {
 		if (E.value.array_size > 0) {
-			size = ShaderLanguage::get_type_size(E.value.type) * E.value.array_size;
+			size = ShaderLanguage::get_datatype_size(E.value.type) * E.value.array_size;
 			int m = (16 * E.value.array_size);
 			int m = (16 * E.value.array_size);
 			if ((size % m) != 0U) {
 			if ((size % m) != 0U) {
 				size += m - (size % m);
 				size += m - (size % m);
 			}
 			}
 		} else {
 		} else {
-			size = ShaderLanguage::get_type_size(E.value.type);
+			size = ShaderLanguage::get_datatype_size(E.value.type);
 		}
 		}
 		ERR_CONTINUE(offset + size > p_buffer_size);
 		ERR_CONTINUE(offset + size > p_buffer_size);
 #endif
 #endif

+ 3 - 78
servers/rendering/renderer_rd/shader_compiler_rd.cpp

@@ -54,81 +54,6 @@ static String _typestr(SL::DataType p_type) {
 	return type;
 	return type;
 }
 }
 
 
-static int _get_datatype_size(SL::DataType p_type) {
-	switch (p_type) {
-		case SL::TYPE_VOID:
-			return 0;
-		case SL::TYPE_BOOL:
-			return 4;
-		case SL::TYPE_BVEC2:
-			return 8;
-		case SL::TYPE_BVEC3:
-			return 12;
-		case SL::TYPE_BVEC4:
-			return 16;
-		case SL::TYPE_INT:
-			return 4;
-		case SL::TYPE_IVEC2:
-			return 8;
-		case SL::TYPE_IVEC3:
-			return 12;
-		case SL::TYPE_IVEC4:
-			return 16;
-		case SL::TYPE_UINT:
-			return 4;
-		case SL::TYPE_UVEC2:
-			return 8;
-		case SL::TYPE_UVEC3:
-			return 12;
-		case SL::TYPE_UVEC4:
-			return 16;
-		case SL::TYPE_FLOAT:
-			return 4;
-		case SL::TYPE_VEC2:
-			return 8;
-		case SL::TYPE_VEC3:
-			return 12;
-		case SL::TYPE_VEC4:
-			return 16;
-		case SL::TYPE_MAT2:
-			return 32; // 4 * 4 + 4 * 4
-		case SL::TYPE_MAT3:
-			return 48; // 4 * 4 + 4 * 4 + 4 * 4
-		case SL::TYPE_MAT4:
-			return 64;
-		case SL::TYPE_SAMPLER2D:
-			return 16;
-		case SL::TYPE_ISAMPLER2D:
-			return 16;
-		case SL::TYPE_USAMPLER2D:
-			return 16;
-		case SL::TYPE_SAMPLER2DARRAY:
-			return 16;
-		case SL::TYPE_ISAMPLER2DARRAY:
-			return 16;
-		case SL::TYPE_USAMPLER2DARRAY:
-			return 16;
-		case SL::TYPE_SAMPLER3D:
-			return 16;
-		case SL::TYPE_ISAMPLER3D:
-			return 16;
-		case SL::TYPE_USAMPLER3D:
-			return 16;
-		case SL::TYPE_SAMPLERCUBE:
-			return 16;
-		case SL::TYPE_SAMPLERCUBEARRAY:
-			return 16;
-		case SL::TYPE_STRUCT:
-			return 0;
-
-		case SL::TYPE_MAX: {
-			ERR_FAIL_V(0);
-		};
-	}
-
-	ERR_FAIL_V(0);
-}
-
 static int _get_datatype_alignment(SL::DataType p_type) {
 static int _get_datatype_alignment(SL::DataType p_type) {
 	switch (p_type) {
 	switch (p_type) {
 		case SL::TYPE_VOID:
 		case SL::TYPE_VOID:
@@ -658,12 +583,12 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
 					uniform_defines.write[uniform.order] = ucode;
 					uniform_defines.write[uniform.order] = ucode;
 					if (is_buffer_global) {
 					if (is_buffer_global) {
 						//globals are indices into the global table
 						//globals are indices into the global table
-						uniform_sizes.write[uniform.order] = _get_datatype_size(ShaderLanguage::TYPE_UINT);
+						uniform_sizes.write[uniform.order] = ShaderLanguage::get_datatype_size(ShaderLanguage::TYPE_UINT);
 						uniform_alignments.write[uniform.order] = _get_datatype_alignment(ShaderLanguage::TYPE_UINT);
 						uniform_alignments.write[uniform.order] = _get_datatype_alignment(ShaderLanguage::TYPE_UINT);
 					} else {
 					} else {
 						// The following code enforces a 16-byte alignment of uniform arrays.
 						// The following code enforces a 16-byte alignment of uniform arrays.
 						if (uniform.array_size > 0) {
 						if (uniform.array_size > 0) {
-							int size = _get_datatype_size(uniform.type) * uniform.array_size;
+							int size = ShaderLanguage::get_datatype_size(uniform.type) * uniform.array_size;
 							int m = (16 * uniform.array_size);
 							int m = (16 * uniform.array_size);
 							if ((size % m) != 0) {
 							if ((size % m) != 0) {
 								size += m - (size % m);
 								size += m - (size % m);
@@ -671,7 +596,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
 							uniform_sizes.write[uniform.order] = size;
 							uniform_sizes.write[uniform.order] = size;
 							uniform_alignments.write[uniform.order] = 16;
 							uniform_alignments.write[uniform.order] = 16;
 						} else {
 						} else {
-							uniform_sizes.write[uniform.order] = _get_datatype_size(uniform.type);
+							uniform_sizes.write[uniform.order] = ShaderLanguage::get_datatype_size(uniform.type);
 							uniform_alignments.write[uniform.order] = _get_datatype_alignment(uniform.type);
 							uniform_alignments.write[uniform.order] = _get_datatype_alignment(uniform.type);
 						}
 						}
 					}
 					}

+ 67 - 21
servers/rendering/shader_language.cpp

@@ -3866,55 +3866,77 @@ PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform
 	return pi;
 	return pi;
 }
 }
 
 
-uint32_t ShaderLanguage::get_type_size(DataType p_type) {
+uint32_t ShaderLanguage::get_datatype_size(ShaderLanguage::DataType p_type) {
 	switch (p_type) {
 	switch (p_type) {
 		case TYPE_VOID:
 		case TYPE_VOID:
 			return 0;
 			return 0;
 		case TYPE_BOOL:
 		case TYPE_BOOL:
-		case TYPE_INT:
-		case TYPE_UINT:
-		case TYPE_FLOAT:
 			return 4;
 			return 4;
 		case TYPE_BVEC2:
 		case TYPE_BVEC2:
-		case TYPE_IVEC2:
-		case TYPE_UVEC2:
-		case TYPE_VEC2:
 			return 8;
 			return 8;
 		case TYPE_BVEC3:
 		case TYPE_BVEC3:
-		case TYPE_IVEC3:
-		case TYPE_UVEC3:
-		case TYPE_VEC3:
 			return 12;
 			return 12;
 		case TYPE_BVEC4:
 		case TYPE_BVEC4:
+			return 16;
+		case TYPE_INT:
+			return 4;
+		case TYPE_IVEC2:
+			return 8;
+		case TYPE_IVEC3:
+			return 12;
 		case TYPE_IVEC4:
 		case TYPE_IVEC4:
+			return 16;
+		case TYPE_UINT:
+			return 4;
+		case TYPE_UVEC2:
+			return 8;
+		case TYPE_UVEC3:
+			return 12;
 		case TYPE_UVEC4:
 		case TYPE_UVEC4:
+			return 16;
+		case TYPE_FLOAT:
+			return 4;
+		case TYPE_VEC2:
+			return 8;
+		case TYPE_VEC3:
+			return 12;
 		case TYPE_VEC4:
 		case TYPE_VEC4:
 			return 16;
 			return 16;
 		case TYPE_MAT2:
 		case TYPE_MAT2:
-			return 8;
+			return 32; // 4 * 4 + 4 * 4
 		case TYPE_MAT3:
 		case TYPE_MAT3:
-			return 12;
+			return 48; // 4 * 4 + 4 * 4 + 4 * 4
 		case TYPE_MAT4:
 		case TYPE_MAT4:
-			return 16;
+			return 64;
 		case TYPE_SAMPLER2D:
 		case TYPE_SAMPLER2D:
+			return 16;
 		case TYPE_ISAMPLER2D:
 		case TYPE_ISAMPLER2D:
+			return 16;
 		case TYPE_USAMPLER2D:
 		case TYPE_USAMPLER2D:
+			return 16;
 		case TYPE_SAMPLER2DARRAY:
 		case TYPE_SAMPLER2DARRAY:
+			return 16;
 		case TYPE_ISAMPLER2DARRAY:
 		case TYPE_ISAMPLER2DARRAY:
+			return 16;
 		case TYPE_USAMPLER2DARRAY:
 		case TYPE_USAMPLER2DARRAY:
+			return 16;
 		case TYPE_SAMPLER3D:
 		case TYPE_SAMPLER3D:
+			return 16;
 		case TYPE_ISAMPLER3D:
 		case TYPE_ISAMPLER3D:
+			return 16;
 		case TYPE_USAMPLER3D:
 		case TYPE_USAMPLER3D:
+			return 16;
 		case TYPE_SAMPLERCUBE:
 		case TYPE_SAMPLERCUBE:
+			return 16;
 		case TYPE_SAMPLERCUBEARRAY:
 		case TYPE_SAMPLERCUBEARRAY:
-			return 4; //not really, but useful for indices
+			return 16;
 		case TYPE_STRUCT:
 		case TYPE_STRUCT:
-			// FIXME: Implement.
-			return 0;
-		case ShaderLanguage::TYPE_MAX:
 			return 0;
 			return 0;
+		case TYPE_MAX: {
+			ERR_FAIL_V(0);
+		};
 	}
 	}
-	return 0;
+	ERR_FAIL_V(0);
 }
 }
 
 
 void ShaderLanguage::get_keyword_list(List<String> *r_keywords) {
 void ShaderLanguage::get_keyword_list(List<String> *r_keywords) {
@@ -5309,7 +5331,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
 				_set_error("Expected expression, found: " + get_token_text(tk));
 				_set_error("Expected expression, found: " + get_token_text(tk));
 				return nullptr;
 				return nullptr;
 			} else {
 			} else {
-#if DEBUG_ENABLED
+#ifdef DEBUG_ENABLED
 				if (check_warnings && HAS_WARNING(ShaderWarning::FORMATTING_ERROR_FLAG)) {
 				if (check_warnings && HAS_WARNING(ShaderWarning::FORMATTING_ERROR_FLAG)) {
 					_add_line_warning(ShaderWarning::FORMATTING_ERROR, "Empty statement. Remove ';' to fix this warning.");
 					_add_line_warning(ShaderWarning::FORMATTING_ERROR, "Empty statement. Remove ';' to fix this warning.");
 				}
 				}
@@ -6120,7 +6142,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
 					ERR_FAIL_V(nullptr); //unexpected operator
 					ERR_FAIL_V(nullptr); //unexpected operator
 			}
 			}
 
 
-#if DEBUG_ENABLED
+#ifdef DEBUG_ENABLED
 			if (check_warnings && HAS_WARNING(ShaderWarning::FLOAT_COMPARISON_FLAG) && (op == OP_EQUAL || op == OP_NOT_EQUAL) &&
 			if (check_warnings && HAS_WARNING(ShaderWarning::FLOAT_COMPARISON_FLAG) && (op == OP_EQUAL || op == OP_NOT_EQUAL) &&
 					(!expression[i - 1].is_op && !expression[i + 1].is_op) &&
 					(!expression[i - 1].is_op && !expression[i + 1].is_op) &&
 					(expression[i - 1].node->get_datatype() == TYPE_FLOAT && expression[i + 1].node->get_datatype() == TYPE_FLOAT)) {
 					(expression[i - 1].node->get_datatype() == TYPE_FLOAT && expression[i + 1].node->get_datatype() == TYPE_FLOAT)) {
@@ -7571,6 +7593,10 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
 	int texture_binding = 0;
 	int texture_binding = 0;
 	int uniforms = 0;
 	int uniforms = 0;
 	int instance_index = 0;
 	int instance_index = 0;
+#ifdef DEBUG_ENABLED
+	int uniform_buffer_size = 0;
+	int max_uniform_buffer_size = RenderingDevice::get_singleton()->limit_get(RenderingDevice::LIMIT_MAX_UNIFORM_BUFFER_SIZE);
+#endif // DEBUG_ENABLED
 	ShaderNode::Uniform::Scope uniform_scope = ShaderNode::Uniform::SCOPE_LOCAL;
 	ShaderNode::Uniform::Scope uniform_scope = ShaderNode::Uniform::SCOPE_LOCAL;
 
 
 	stages = &p_functions;
 	stages = &p_functions;
@@ -7971,6 +7997,18 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
 						uniform2.texture_order = -1;
 						uniform2.texture_order = -1;
 						if (uniform_scope != ShaderNode::Uniform::SCOPE_INSTANCE) {
 						if (uniform_scope != ShaderNode::Uniform::SCOPE_INSTANCE) {
 							uniform2.order = uniforms++;
 							uniform2.order = uniforms++;
+#ifdef DEBUG_ENABLED
+							if (uniform2.array_size > 0) {
+								int size = get_datatype_size(uniform2.type) * uniform2.array_size;
+								int m = (16 * uniform2.array_size);
+								if ((size % m) != 0U) {
+									size += m - (size % m);
+								}
+								uniform_buffer_size += size;
+							} else {
+								uniform_buffer_size += get_datatype_size(uniform2.type);
+							}
+#endif // DEBUG_ENABLED
 						}
 						}
 					}
 					}
 
 
@@ -8980,6 +9018,14 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
 		tk = _get_token();
 		tk = _get_token();
 	}
 	}
 
 
+#ifdef DEBUG_ENABLED
+	if (HAS_WARNING(ShaderWarning::DEVICE_LIMIT_EXCEEDED) && (uniform_buffer_size > max_uniform_buffer_size)) {
+		Vector<Variant> args;
+		args.push_back(uniform_buffer_size);
+		args.push_back(max_uniform_buffer_size);
+		_add_global_warning(ShaderWarning::DEVICE_LIMIT_EXCEEDED, "uniform buffer", args);
+	}
+#endif // DEBUG_ENABLED
 	return OK;
 	return OK;
 }
 }
 
 
@@ -9687,7 +9733,7 @@ ShaderLanguage::ShaderLanguage() {
 	nodes = nullptr;
 	nodes = nullptr;
 	completion_class = TAG_GLOBAL;
 	completion_class = TAG_GLOBAL;
 
 
-#if DEBUG_ENABLED
+#ifdef DEBUG_ENABLED
 	warnings_check_map.insert(ShaderWarning::UNUSED_CONSTANT, &used_constants);
 	warnings_check_map.insert(ShaderWarning::UNUSED_CONSTANT, &used_constants);
 	warnings_check_map.insert(ShaderWarning::UNUSED_FUNCTION, &used_functions);
 	warnings_check_map.insert(ShaderWarning::UNUSED_FUNCTION, &used_functions);
 	warnings_check_map.insert(ShaderWarning::UNUSED_STRUCT, &used_structs);
 	warnings_check_map.insert(ShaderWarning::UNUSED_STRUCT, &used_structs);

+ 8 - 5
servers/rendering/shader_language.h

@@ -787,7 +787,7 @@ public:
 	static bool is_sampler_type(DataType p_type);
 	static bool is_sampler_type(DataType p_type);
 	static Variant constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, int p_array_size, ShaderLanguage::ShaderNode::Uniform::Hint p_hint = ShaderLanguage::ShaderNode::Uniform::HINT_NONE);
 	static Variant constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, int p_array_size, ShaderLanguage::ShaderNode::Uniform::Hint p_hint = ShaderLanguage::ShaderNode::Uniform::HINT_NONE);
 	static PropertyInfo uniform_to_property_info(const ShaderNode::Uniform &p_uniform);
 	static PropertyInfo uniform_to_property_info(const ShaderNode::Uniform &p_uniform);
-	static uint32_t get_type_size(DataType p_type);
+	static uint32_t get_datatype_size(DataType p_type);
 
 
 	static void get_keyword_list(List<String> *r_keywords);
 	static void get_keyword_list(List<String> *r_keywords);
 	static bool is_control_flow_keyword(String p_keyword);
 	static bool is_control_flow_keyword(String p_keyword);
@@ -919,11 +919,14 @@ private:
 	bool check_warnings = false;
 	bool check_warnings = false;
 	uint32_t warning_flags;
 	uint32_t warning_flags;
 
 
-	void _add_line_warning(ShaderWarning::Code p_code, const StringName &p_subject = "") {
-		warnings.push_back(ShaderWarning(p_code, tk_line, p_subject));
+	void _add_line_warning(ShaderWarning::Code p_code, const StringName &p_subject = "", const Vector<Variant> &p_extra_args = Vector<Variant>()) {
+		warnings.push_back(ShaderWarning(p_code, tk_line, p_subject, p_extra_args));
 	}
 	}
-	void _add_warning(ShaderWarning::Code p_code, int p_line, const StringName &p_subject = "") {
-		warnings.push_back(ShaderWarning(p_code, p_line, p_subject));
+	void _add_global_warning(ShaderWarning::Code p_code, const StringName &p_subject = "", const Vector<Variant> &p_extra_args = Vector<Variant>()) {
+		warnings.push_back(ShaderWarning(p_code, -1, p_subject, p_extra_args));
+	}
+	void _add_warning(ShaderWarning::Code p_code, int p_line, const StringName &p_subject = "", const Vector<Variant> &p_extra_args = Vector<Variant>()) {
+		warnings.push_back(ShaderWarning(p_code, p_line, p_subject, p_extra_args));
 	}
 	}
 	void _check_warning_accums();
 	void _check_warning_accums();
 #endif // DEBUG_ENABLED
 #endif // DEBUG_ENABLED

+ 10 - 2
servers/rendering/shader_warnings.cpp

@@ -63,6 +63,8 @@ String ShaderWarning::get_message() const {
 			return vformat("The local variable '%s' is declared but never used.", subject);
 			return vformat("The local variable '%s' is declared but never used.", subject);
 		case FORMATTING_ERROR:
 		case FORMATTING_ERROR:
 			return subject;
 			return subject;
+		case DEVICE_LIMIT_EXCEEDED:
+			return vformat("The total size of the %s for this shader on this device has been exceeded (%s/%s). The shader may not work correctly.", subject, (int)extra_args[0], (int)extra_args[1]);
 		default:
 		default:
 			break;
 			break;
 	}
 	}
@@ -73,6 +75,10 @@ String ShaderWarning::get_name() const {
 	return get_name_from_code(code);
 	return get_name_from_code(code);
 }
 }
 
 
+Vector<Variant> ShaderWarning::get_extra_args() const {
+	return extra_args;
+}
+
 String ShaderWarning::get_name_from_code(Code p_code) {
 String ShaderWarning::get_name_from_code(Code p_code) {
 	ERR_FAIL_INDEX_V(p_code, WARNING_MAX, String());
 	ERR_FAIL_INDEX_V(p_code, WARNING_MAX, String());
 
 
@@ -85,6 +91,7 @@ String ShaderWarning::get_name_from_code(Code p_code) {
 		"UNUSED_VARYING",
 		"UNUSED_VARYING",
 		"UNUSED_LOCAL_VARIABLE",
 		"UNUSED_LOCAL_VARIABLE",
 		"FORMATTING_ERROR",
 		"FORMATTING_ERROR",
+		"DEVICE_LIMIT_EXCEEDED",
 	};
 	};
 
 
 	static_assert((sizeof(names) / sizeof(*names)) == WARNING_MAX, "Amount of warning types don't match the amount of warning names.");
 	static_assert((sizeof(names) / sizeof(*names)) == WARNING_MAX, "Amount of warning types don't match the amount of warning names.");
@@ -114,6 +121,7 @@ static void init_code_to_flags_map() {
 	code_to_flags_map->insert(ShaderWarning::UNUSED_VARYING, ShaderWarning::UNUSED_VARYING_FLAG);
 	code_to_flags_map->insert(ShaderWarning::UNUSED_VARYING, ShaderWarning::UNUSED_VARYING_FLAG);
 	code_to_flags_map->insert(ShaderWarning::UNUSED_LOCAL_VARIABLE, ShaderWarning::UNUSED_LOCAL_VARIABLE_FLAG);
 	code_to_flags_map->insert(ShaderWarning::UNUSED_LOCAL_VARIABLE, ShaderWarning::UNUSED_LOCAL_VARIABLE_FLAG);
 	code_to_flags_map->insert(ShaderWarning::FORMATTING_ERROR, ShaderWarning::FORMATTING_ERROR_FLAG);
 	code_to_flags_map->insert(ShaderWarning::FORMATTING_ERROR, ShaderWarning::FORMATTING_ERROR_FLAG);
+	code_to_flags_map->insert(ShaderWarning::DEVICE_LIMIT_EXCEEDED, ShaderWarning::DEVICE_LIMIT_EXCEEDED_FLAG);
 }
 }
 
 
 ShaderWarning::CodeFlags ShaderWarning::get_flags_from_codemap(const Map<Code, bool> &p_map) {
 ShaderWarning::CodeFlags ShaderWarning::get_flags_from_codemap(const Map<Code, bool> &p_map) {
@@ -132,8 +140,8 @@ ShaderWarning::CodeFlags ShaderWarning::get_flags_from_codemap(const Map<Code, b
 	return (CodeFlags)result;
 	return (CodeFlags)result;
 }
 }
 
 
-ShaderWarning::ShaderWarning(Code p_code, int p_line, const StringName &p_subject) :
-		code(p_code), line(p_line), subject(p_subject) {
+ShaderWarning::ShaderWarning(Code p_code, int p_line, const StringName &p_subject, const Vector<Variant> &p_extra_args) :
+		code(p_code), line(p_line), subject(p_subject), extra_args(p_extra_args) {
 }
 }
 
 
 #endif // DEBUG_ENABLED
 #endif // DEBUG_ENABLED

+ 6 - 1
servers/rendering/shader_warnings.h

@@ -36,6 +36,7 @@
 #include "core/string/string_name.h"
 #include "core/string/string_name.h"
 #include "core/templates/list.h"
 #include "core/templates/list.h"
 #include "core/templates/map.h"
 #include "core/templates/map.h"
+#include "core/variant/variant.h"
 
 
 class ShaderWarning {
 class ShaderWarning {
 public:
 public:
@@ -48,6 +49,7 @@ public:
 		UNUSED_VARYING,
 		UNUSED_VARYING,
 		UNUSED_LOCAL_VARIABLE,
 		UNUSED_LOCAL_VARIABLE,
 		FORMATTING_ERROR,
 		FORMATTING_ERROR,
+		DEVICE_LIMIT_EXCEEDED,
 		WARNING_MAX,
 		WARNING_MAX,
 	};
 	};
 
 
@@ -61,12 +63,14 @@ public:
 		UNUSED_VARYING_FLAG = 32U,
 		UNUSED_VARYING_FLAG = 32U,
 		UNUSED_LOCAL_VARIABLE_FLAG = 64U,
 		UNUSED_LOCAL_VARIABLE_FLAG = 64U,
 		FORMATTING_ERROR_FLAG = 128U,
 		FORMATTING_ERROR_FLAG = 128U,
+		DEVICE_LIMIT_EXCEEDED_FLAG = 256U,
 	};
 	};
 
 
 private:
 private:
 	Code code;
 	Code code;
 	int line;
 	int line;
 	StringName subject;
 	StringName subject;
+	Vector<Variant> extra_args;
 
 
 public:
 public:
 	Code get_code() const;
 	Code get_code() const;
@@ -74,12 +78,13 @@ public:
 	const StringName &get_subject() const;
 	const StringName &get_subject() const;
 	String get_message() const;
 	String get_message() const;
 	String get_name() const;
 	String get_name() const;
+	Vector<Variant> get_extra_args() const;
 
 
 	static String get_name_from_code(Code p_code);
 	static String get_name_from_code(Code p_code);
 	static Code get_code_from_name(const String &p_name);
 	static Code get_code_from_name(const String &p_name);
 	static CodeFlags get_flags_from_codemap(const Map<Code, bool> &p_map);
 	static CodeFlags get_flags_from_codemap(const Map<Code, bool> &p_map);
 
 
-	ShaderWarning(Code p_code = WARNING_MAX, int p_line = -1, const StringName &p_subject = "");
+	ShaderWarning(Code p_code = WARNING_MAX, int p_line = -1, const StringName &p_subject = "", const Vector<Variant> &p_extra_args = Vector<Variant>());
 };
 };
 
 
 #endif // DEBUG_ENABLED
 #endif // DEBUG_ENABLED