Add a shader warning when the uniform buffer limit is exceeded

This commit is contained in:
Yuri Roubinsky 2021-12-22 10:15:12 +03:00
parent 9221c0f8ad
commit fd9c92d4ab
9 changed files with 107 additions and 115 deletions

View File

@ -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.

View File

@ -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");

View File

@ -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);

View File

@ -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

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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