mirror of
https://github.com/godotengine/godot.git
synced 2024-11-22 04:06:14 +00:00
Add a shader warning when the uniform buffer limit is exceeded
This commit is contained in:
parent
9221c0f8ad
commit
fd9c92d4ab
@ -293,15 +293,20 @@ void ShaderTextEditor::_update_warning_panel() {
|
||||
}
|
||||
|
||||
warning_count++;
|
||||
int line = w.get_line();
|
||||
|
||||
// First 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->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(); // Meta goto.
|
||||
warnings_panel->pop(); // Cell.
|
||||
|
||||
// Second cell.
|
||||
|
@ -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(" --profiling Enable profiling in the script debugger.\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");
|
||||
#endif
|
||||
OS::get_singleton()->print(" --remote-debug <uri> Remote debug (<protocol>://<host/IP>[:<port>], e.g. tcp://127.0.0.1:6007).\n");
|
||||
|
@ -1591,7 +1591,7 @@ void AudioServer::set_bus_layout(const Ref<AudioBusLayout> &p_bus_layout) {
|
||||
Bus::Effect bfx;
|
||||
bfx.effect = fx;
|
||||
bfx.enabled = p_bus_layout->buses[i].effects[j].enabled;
|
||||
#if DEBUG_ENABLED
|
||||
#ifdef DEBUG_ENABLED
|
||||
bfx.prof_time = 0;
|
||||
#endif
|
||||
bus->effects.push_back(bfx);
|
||||
|
@ -2655,13 +2655,13 @@ void RendererStorageRD::MaterialData::update_uniform_buffer(const Map<StringName
|
||||
uint32_t size = 0U;
|
||||
// The following code enforces a 16-byte alignment of uniform arrays.
|
||||
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);
|
||||
if ((size % m) != 0U) {
|
||||
size += m - (size % m);
|
||||
}
|
||||
} else {
|
||||
size = ShaderLanguage::get_type_size(E.value.type);
|
||||
size = ShaderLanguage::get_datatype_size(E.value.type);
|
||||
}
|
||||
ERR_CONTINUE(offset + size > p_buffer_size);
|
||||
#endif
|
||||
|
@ -54,81 +54,6 @@ static String _typestr(SL::DataType p_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) {
|
||||
switch (p_type) {
|
||||
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;
|
||||
if (is_buffer_global) {
|
||||
//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);
|
||||
} else {
|
||||
// The following code enforces a 16-byte alignment of uniform arrays.
|
||||
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);
|
||||
if ((size % m) != 0) {
|
||||
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_alignments.write[uniform.order] = 16;
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
@ -3866,55 +3866,77 @@ PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform
|
||||
return pi;
|
||||
}
|
||||
|
||||
uint32_t ShaderLanguage::get_type_size(DataType p_type) {
|
||||
uint32_t ShaderLanguage::get_datatype_size(ShaderLanguage::DataType p_type) {
|
||||
switch (p_type) {
|
||||
case TYPE_VOID:
|
||||
return 0;
|
||||
case TYPE_BOOL:
|
||||
case TYPE_INT:
|
||||
case TYPE_UINT:
|
||||
case TYPE_FLOAT:
|
||||
return 4;
|
||||
case TYPE_BVEC2:
|
||||
case TYPE_IVEC2:
|
||||
case TYPE_UVEC2:
|
||||
case TYPE_VEC2:
|
||||
return 8;
|
||||
case TYPE_BVEC3:
|
||||
case TYPE_IVEC3:
|
||||
case TYPE_UVEC3:
|
||||
case TYPE_VEC3:
|
||||
return 12;
|
||||
case TYPE_BVEC4:
|
||||
return 16;
|
||||
case TYPE_INT:
|
||||
return 4;
|
||||
case TYPE_IVEC2:
|
||||
return 8;
|
||||
case TYPE_IVEC3:
|
||||
return 12;
|
||||
case TYPE_IVEC4:
|
||||
return 16;
|
||||
case TYPE_UINT:
|
||||
return 4;
|
||||
case TYPE_UVEC2:
|
||||
return 8;
|
||||
case TYPE_UVEC3:
|
||||
return 12;
|
||||
case TYPE_UVEC4:
|
||||
return 16;
|
||||
case TYPE_FLOAT:
|
||||
return 4;
|
||||
case TYPE_VEC2:
|
||||
return 8;
|
||||
case TYPE_VEC3:
|
||||
return 12;
|
||||
case TYPE_VEC4:
|
||||
return 16;
|
||||
case TYPE_MAT2:
|
||||
return 8;
|
||||
return 32; // 4 * 4 + 4 * 4
|
||||
case TYPE_MAT3:
|
||||
return 12;
|
||||
return 48; // 4 * 4 + 4 * 4 + 4 * 4
|
||||
case TYPE_MAT4:
|
||||
return 16;
|
||||
return 64;
|
||||
case TYPE_SAMPLER2D:
|
||||
return 16;
|
||||
case TYPE_ISAMPLER2D:
|
||||
return 16;
|
||||
case TYPE_USAMPLER2D:
|
||||
return 16;
|
||||
case TYPE_SAMPLER2DARRAY:
|
||||
return 16;
|
||||
case TYPE_ISAMPLER2DARRAY:
|
||||
return 16;
|
||||
case TYPE_USAMPLER2DARRAY:
|
||||
return 16;
|
||||
case TYPE_SAMPLER3D:
|
||||
return 16;
|
||||
case TYPE_ISAMPLER3D:
|
||||
return 16;
|
||||
case TYPE_USAMPLER3D:
|
||||
return 16;
|
||||
case TYPE_SAMPLERCUBE:
|
||||
return 16;
|
||||
case TYPE_SAMPLERCUBEARRAY:
|
||||
return 4; //not really, but useful for indices
|
||||
return 16;
|
||||
case TYPE_STRUCT:
|
||||
// FIXME: Implement.
|
||||
return 0;
|
||||
case ShaderLanguage::TYPE_MAX:
|
||||
return 0;
|
||||
case TYPE_MAX: {
|
||||
ERR_FAIL_V(0);
|
||||
};
|
||||
}
|
||||
return 0;
|
||||
ERR_FAIL_V(0);
|
||||
}
|
||||
|
||||
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));
|
||||
return nullptr;
|
||||
} else {
|
||||
#if DEBUG_ENABLED
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (check_warnings && HAS_WARNING(ShaderWarning::FORMATTING_ERROR_FLAG)) {
|
||||
_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
|
||||
}
|
||||
|
||||
#if DEBUG_ENABLED
|
||||
#ifdef DEBUG_ENABLED
|
||||
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].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 uniforms = 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;
|
||||
|
||||
stages = &p_functions;
|
||||
@ -7971,6 +7997,18 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
||||
uniform2.texture_order = -1;
|
||||
if (uniform_scope != ShaderNode::Uniform::SCOPE_INSTANCE) {
|
||||
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();
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
@ -9687,7 +9733,7 @@ ShaderLanguage::ShaderLanguage() {
|
||||
nodes = nullptr;
|
||||
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_FUNCTION, &used_functions);
|
||||
warnings_check_map.insert(ShaderWarning::UNUSED_STRUCT, &used_structs);
|
||||
|
@ -787,7 +787,7 @@ public:
|
||||
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 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 bool is_control_flow_keyword(String p_keyword);
|
||||
@ -919,11 +919,14 @@ private:
|
||||
bool check_warnings = false;
|
||||
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();
|
||||
#endif // DEBUG_ENABLED
|
||||
|
@ -63,6 +63,8 @@ String ShaderWarning::get_message() const {
|
||||
return vformat("The local variable '%s' is declared but never used.", subject);
|
||||
case FORMATTING_ERROR:
|
||||
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:
|
||||
break;
|
||||
}
|
||||
@ -73,6 +75,10 @@ String ShaderWarning::get_name() const {
|
||||
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) {
|
||||
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_LOCAL_VARIABLE",
|
||||
"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.");
|
||||
@ -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_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::DEVICE_LIMIT_EXCEEDED, ShaderWarning::DEVICE_LIMIT_EXCEEDED_FLAG);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "core/string/string_name.h"
|
||||
#include "core/templates/list.h"
|
||||
#include "core/templates/map.h"
|
||||
#include "core/variant/variant.h"
|
||||
|
||||
class ShaderWarning {
|
||||
public:
|
||||
@ -48,6 +49,7 @@ public:
|
||||
UNUSED_VARYING,
|
||||
UNUSED_LOCAL_VARIABLE,
|
||||
FORMATTING_ERROR,
|
||||
DEVICE_LIMIT_EXCEEDED,
|
||||
WARNING_MAX,
|
||||
};
|
||||
|
||||
@ -61,12 +63,14 @@ public:
|
||||
UNUSED_VARYING_FLAG = 32U,
|
||||
UNUSED_LOCAL_VARIABLE_FLAG = 64U,
|
||||
FORMATTING_ERROR_FLAG = 128U,
|
||||
DEVICE_LIMIT_EXCEEDED_FLAG = 256U,
|
||||
};
|
||||
|
||||
private:
|
||||
Code code;
|
||||
int line;
|
||||
StringName subject;
|
||||
Vector<Variant> extra_args;
|
||||
|
||||
public:
|
||||
Code get_code() const;
|
||||
@ -74,12 +78,13 @@ public:
|
||||
const StringName &get_subject() const;
|
||||
String get_message() const;
|
||||
String get_name() const;
|
||||
Vector<Variant> get_extra_args() const;
|
||||
|
||||
static String get_name_from_code(Code p_code);
|
||||
static Code get_code_from_name(const String &p_name);
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user