mirror of
https://github.com/godotengine/godot.git
synced 2025-11-01 06:01:14 +00:00
Basic warning support implementation for the Godot Shading Language.
This commit is contained in:
parent
4828667759
commit
084648bd18
6 changed files with 569 additions and 18 deletions
|
|
@ -33,6 +33,8 @@
|
|||
#include "core/string/print_string.h"
|
||||
#include "servers/rendering_server.h"
|
||||
|
||||
#define HAS_WARNING(flag) (warning_flags & flag)
|
||||
|
||||
static bool _is_text_char(char32_t c) {
|
||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
|
||||
}
|
||||
|
|
@ -901,6 +903,8 @@ bool ShaderLanguage::is_token_nonvoid_datatype(TokenType p_type) {
|
|||
|
||||
void ShaderLanguage::clear() {
|
||||
current_function = StringName();
|
||||
last_name = StringName();
|
||||
last_type = IDENTIFIER_MAX;
|
||||
|
||||
completion_type = COMPLETION_NONE;
|
||||
completion_block = nullptr;
|
||||
|
|
@ -908,12 +912,20 @@ void ShaderLanguage::clear() {
|
|||
completion_class = SubClassTag::TAG_GLOBAL;
|
||||
completion_struct = StringName();
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
used_constants.clear();
|
||||
used_varyings.clear();
|
||||
used_uniforms.clear();
|
||||
used_functions.clear();
|
||||
used_structs.clear();
|
||||
warnings.clear();
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
error_line = 0;
|
||||
tk_line = 1;
|
||||
char_idx = 0;
|
||||
error_set = false;
|
||||
error_str = "";
|
||||
last_const = false;
|
||||
while (nodes) {
|
||||
Node *n = nodes;
|
||||
nodes = nodes->next;
|
||||
|
|
@ -921,6 +933,35 @@ void ShaderLanguage::clear() {
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
void ShaderLanguage::_parse_used_identifier(const StringName &p_identifier, IdentifierType p_type) {
|
||||
switch (p_type) {
|
||||
case IdentifierType::IDENTIFIER_CONSTANT:
|
||||
if (HAS_WARNING(ShaderWarning::UNUSED_CONSTANT_FLAG) && used_constants.has(p_identifier)) {
|
||||
used_constants[p_identifier].used = true;
|
||||
}
|
||||
break;
|
||||
case IdentifierType::IDENTIFIER_VARYING:
|
||||
if (HAS_WARNING(ShaderWarning::UNUSED_VARYING_FLAG) && used_varyings.has(p_identifier)) {
|
||||
used_varyings[p_identifier].used = true;
|
||||
}
|
||||
break;
|
||||
case IdentifierType::IDENTIFIER_UNIFORM:
|
||||
if (HAS_WARNING(ShaderWarning::UNUSED_UNIFORM_FLAG) && used_uniforms.has(p_identifier)) {
|
||||
used_uniforms[p_identifier].used = true;
|
||||
}
|
||||
break;
|
||||
case IdentifierType::IDENTIFIER_FUNCTION:
|
||||
if (HAS_WARNING(ShaderWarning::UNUSED_FUNCTION_FLAG) && used_functions.has(p_identifier)) {
|
||||
used_functions[p_identifier].used = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_reassign, const FunctionInfo &p_function_info, const StringName &p_identifier, DataType *r_data_type, IdentifierType *r_type, bool *r_is_const, int *r_array_size, StringName *r_struct_name, ConstantNode::Value *r_constant_value) {
|
||||
if (p_function_info.built_ins.has(p_identifier)) {
|
||||
if (r_data_type) {
|
||||
|
|
@ -3602,6 +3643,11 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
|
|||
|
||||
if (shader->structs.has(identifier)) {
|
||||
pstruct = shader->structs[identifier].shader_struct;
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_STRUCT_FLAG) && used_structs.has(identifier)) {
|
||||
used_structs[identifier].used = true;
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
struct_init = true;
|
||||
}
|
||||
|
||||
|
|
@ -3825,11 +3871,17 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
|
|||
}
|
||||
}
|
||||
expr = func;
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (check_warnings) {
|
||||
_parse_used_identifier(name, IdentifierType::IDENTIFIER_FUNCTION);
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
}
|
||||
} else {
|
||||
//an identifier
|
||||
|
||||
last_const = false;
|
||||
last_name = identifier;
|
||||
last_type = IDENTIFIER_MAX;
|
||||
_set_tkpos(pos);
|
||||
|
||||
DataType data_type;
|
||||
|
|
@ -3874,12 +3926,16 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
|
|||
}
|
||||
}
|
||||
}
|
||||
last_const = is_const;
|
||||
|
||||
if (ident_type == IDENTIFIER_FUNCTION) {
|
||||
_set_error("Can't use function as identifier: " + String(identifier));
|
||||
return nullptr;
|
||||
}
|
||||
if (is_const) {
|
||||
last_type = IDENTIFIER_CONSTANT;
|
||||
} else {
|
||||
last_type = ident_type;
|
||||
}
|
||||
}
|
||||
|
||||
Node *index_expression = nullptr;
|
||||
|
|
@ -3953,7 +4009,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
|
|||
arrname->assign_expression = assign_expression;
|
||||
arrname->is_const = is_const;
|
||||
expr = arrname;
|
||||
|
||||
} else {
|
||||
VariableNode *varname = alloc_node<VariableNode>();
|
||||
varname->name = identifier;
|
||||
|
|
@ -3962,6 +4017,11 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
|
|||
varname->struct_name = struct_name;
|
||||
expr = varname;
|
||||
}
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (check_warnings) {
|
||||
_parse_used_identifier(identifier, ident_type);
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
}
|
||||
} else if (tk.type == TK_OP_ADD) {
|
||||
continue; //this one does nothing
|
||||
|
|
@ -4290,8 +4350,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
|
|||
if (array_size > 0) {
|
||||
tk = _get_token();
|
||||
if (tk.type == TK_OP_ASSIGN) {
|
||||
if (last_const) {
|
||||
last_const = false;
|
||||
if (last_type == IDENTIFIER_CONSTANT) {
|
||||
_set_error("Constants cannot be modified.");
|
||||
return nullptr;
|
||||
}
|
||||
|
|
@ -4648,9 +4707,10 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
|
|||
|
||||
bool unary = false;
|
||||
bool ternary = false;
|
||||
Operator op = expression[i].op;
|
||||
|
||||
int priority;
|
||||
switch (expression[i].op) {
|
||||
switch (op) {
|
||||
case OP_EQUAL:
|
||||
priority = 8;
|
||||
break;
|
||||
|
|
@ -4771,6 +4831,12 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
|
|||
ERR_FAIL_V(nullptr); //unexpected operator
|
||||
}
|
||||
|
||||
#if DEBUG_ENABLED
|
||||
if (check_warnings && HAS_WARNING(ShaderWarning::FLOAT_COMPARISON_FLAG) && (op == OP_EQUAL || op == OP_NOT_EQUAL) && expression[i - 1].node->get_datatype() == TYPE_FLOAT && expression[i + 1].node->get_datatype() == TYPE_FLOAT) {
|
||||
_add_line_warning(ShaderWarning::FLOAT_COMPARISON);
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
if (priority < min_priority) {
|
||||
// < is used for left to right (default)
|
||||
// <= is used for right to left
|
||||
|
|
@ -5483,7 +5549,6 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
|
|||
p_block->statements.push_back(vardecl);
|
||||
|
||||
p_block->variables[name] = var;
|
||||
|
||||
if (tk.type == TK_COMMA) {
|
||||
if (p_block->block_type == BlockNode::BLOCK_TYPE_FOR) {
|
||||
_set_error("Multiple declarations in 'for' loop are not implemented yet.");
|
||||
|
|
@ -6313,7 +6378,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
|||
}
|
||||
shader->structs[st.name] = st;
|
||||
shader->vstructs.push_back(st); // struct's order is important!
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_STRUCT_FLAG)) {
|
||||
used_structs.insert(st.name, Usage(tk_line));
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
} break;
|
||||
case TK_GLOBAL: {
|
||||
tk = _get_token();
|
||||
|
|
@ -6660,6 +6729,12 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
|||
}
|
||||
|
||||
shader->uniforms[name] = uniform2;
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_UNIFORM_FLAG)) {
|
||||
used_uniforms.insert(name, Usage(tk_line));
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
//reset scope for next uniform
|
||||
uniform_scope = ShaderNode::Uniform::SCOPE_LOCAL;
|
||||
|
||||
|
|
@ -6703,6 +6778,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
|||
}
|
||||
|
||||
shader->varyings[name] = varying;
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_VARYING_FLAG)) {
|
||||
used_varyings.insert(name, Usage(tk_line));
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
}
|
||||
|
||||
} break;
|
||||
|
|
@ -7049,6 +7129,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
|||
|
||||
shader->constants[name] = constant;
|
||||
shader->vconstants.push_back(constant);
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_CONSTANT_FLAG)) {
|
||||
used_constants.insert(name, Usage(tk_line));
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
if (tk.type == TK_COMMA) {
|
||||
tk = _get_token();
|
||||
|
|
@ -7110,6 +7195,12 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
|
|||
|
||||
if (p_functions.has(name)) {
|
||||
func_node->can_discard = p_functions[name].can_discard;
|
||||
} else {
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_FUNCTION_FLAG)) {
|
||||
used_functions.insert(name, Usage(tk_line));
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
}
|
||||
|
||||
func_node->body = alloc_node<BlockNode>();
|
||||
|
|
@ -7443,6 +7534,33 @@ String ShaderLanguage::get_shader_type(const String &p_code) {
|
|||
return String();
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
void ShaderLanguage::_check_warning_accums() {
|
||||
for (Map<ShaderWarning::Code, Map<StringName, Usage> *>::Element *E = warnings_check_map.front(); E; E = E->next()) {
|
||||
for (const Map<StringName, Usage>::Element *U = (*E->get()).front(); U; U = U->next()) {
|
||||
if (!U->get().used) {
|
||||
_add_warning(E->key(), U->get().decl_line, U->key());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
List<ShaderWarning>::Element *ShaderLanguage::get_warnings_ptr() {
|
||||
return warnings.front();
|
||||
}
|
||||
void ShaderLanguage::enable_warning_checking(bool p_enabled) {
|
||||
check_warnings = p_enabled;
|
||||
}
|
||||
bool ShaderLanguage::is_warning_checking_enabled() const {
|
||||
return check_warnings;
|
||||
}
|
||||
void ShaderLanguage::set_warning_flags(uint32_t p_flags) {
|
||||
warning_flags = p_flags;
|
||||
}
|
||||
uint32_t ShaderLanguage::get_warning_flags() const {
|
||||
return warning_flags;
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
Error ShaderLanguage::compile(const String &p_code, const Map<StringName, FunctionInfo> &p_functions, const Vector<StringName> &p_render_modes, const VaryingFunctionNames &p_varying_function_names, const Set<String> &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func) {
|
||||
clear();
|
||||
|
||||
|
|
@ -7455,6 +7573,12 @@ Error ShaderLanguage::compile(const String &p_code, const Map<StringName, Functi
|
|||
shader = alloc_node<ShaderNode>();
|
||||
Error err = _parse_shader(p_functions, p_render_modes, p_shader_types);
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (check_warnings) {
|
||||
_check_warning_accums();
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
if (err != OK) {
|
||||
return err;
|
||||
}
|
||||
|
|
@ -7864,6 +7988,14 @@ ShaderLanguage::ShaderNode *ShaderLanguage::get_shader() {
|
|||
ShaderLanguage::ShaderLanguage() {
|
||||
nodes = nullptr;
|
||||
completion_class = TAG_GLOBAL;
|
||||
|
||||
#if 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);
|
||||
warnings_check_map.insert(ShaderWarning::UNUSED_UNIFORM, &used_uniforms);
|
||||
warnings_check_map.insert(ShaderWarning::UNUSED_VARYING, &used_varyings);
|
||||
#endif // DEBUG_ENABLED
|
||||
}
|
||||
|
||||
ShaderLanguage::~ShaderLanguage() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue