X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fglsl%2Fglsl_parser_extras.cpp;h=ae7a365f4b2be5ad37dd6b053f74fa08fcdd77be;hb=2bb91274e2cc2290ce8e790335f1e57b81d9d783;hp=1fa209c03c1f7ec85797e3618d98f6b5b92099bc;hpb=a7d350790b4d0416117bc785aa77de52e9298a01;p=mesa.git diff --git a/src/glsl/glsl_parser_extras.cpp b/src/glsl/glsl_parser_extras.cpp index 1fa209c03c1..ae7a365f4b2 100644 --- a/src/glsl/glsl_parser_extras.cpp +++ b/src/glsl/glsl_parser_extras.cpp @@ -50,7 +50,10 @@ _mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *ctx, this->symbols = new(mem_ctx) glsl_symbol_table; this->info_log = ralloc_strdup(mem_ctx, ""); this->error = false; - this->loop_or_switch_nesting = NULL; + this->loop_nesting_ast = NULL; + this->switch_state.switch_nesting_ast = NULL; + + this->num_builtins_to_link = 0; /* Set default language version and extensions */ this->language_version = 110; @@ -91,6 +94,8 @@ _mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *ctx, && (ctx->Const.GLSLVersion >= 120); this->Const.GLSL_130 = (ctx->API == API_OPENGL) && (ctx->Const.GLSLVersion >= 130); + this->Const.GLSL_140 = (ctx->API == API_OPENGL) + && (ctx->Const.GLSLVersion >= 140); const unsigned lowest_version = (ctx->API == API_OPENGLES2) || ctx->Extensions.ARB_ES2_compatibility @@ -111,6 +116,9 @@ _mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *ctx, } this->supported_version_string = supported; + + if (ctx->Const.ForceGLSLExtensionsWarn) + _mesa_glsl_process_extension("all", NULL, "warn", NULL, this); } const char * @@ -165,111 +173,244 @@ _mesa_glsl_warning(const YYLTYPE *locp, _mesa_glsl_parse_state *state, } +/** + * Enum representing the possible behaviors that can be specified in + * an #extension directive. + */ +enum ext_behavior { + extension_disable, + extension_enable, + extension_require, + extension_warn +}; + +/** + * Element type for _mesa_glsl_supported_extensions + */ +struct _mesa_glsl_extension { + /** + * Name of the extension when referred to in a GLSL extension + * statement + */ + const char *name; + + /** True if this extension is available to vertex shaders */ + bool avail_in_VS; + + /** True if this extension is available to geometry shaders */ + bool avail_in_GS; + + /** True if this extension is available to fragment shaders */ + bool avail_in_FS; + + /** True if this extension is available to desktop GL shaders */ + bool avail_in_GL; + + /** True if this extension is available to GLES shaders */ + bool avail_in_ES; + + /** + * Flag in the gl_extensions struct indicating whether this + * extension is supported by the driver, or + * &gl_extensions::dummy_true if supported by all drivers. + * + * Note: the type (GLboolean gl_extensions::*) is a "pointer to + * member" type, the type-safe alternative to the "offsetof" macro. + * In a nutshell: + * + * - foo bar::* p declares p to be an "offset" to a field of type + * foo that exists within struct bar + * - &bar::baz computes the "offset" of field baz within struct bar + * - x.*p accesses the field of x that exists at "offset" p + * - x->*p is equivalent to (*x).*p + */ + const GLboolean gl_extensions::* supported_flag; + + /** + * Flag in the _mesa_glsl_parse_state struct that should be set + * when this extension is enabled. + * + * See note in _mesa_glsl_extension::supported_flag about "pointer + * to member" types. + */ + bool _mesa_glsl_parse_state::* enable_flag; + + /** + * Flag in the _mesa_glsl_parse_state struct that should be set + * when the shader requests "warn" behavior for this extension. + * + * See note in _mesa_glsl_extension::supported_flag about "pointer + * to member" types. + */ + bool _mesa_glsl_parse_state::* warn_flag; + + + bool compatible_with_state(const _mesa_glsl_parse_state *state) const; + void set_flags(_mesa_glsl_parse_state *state, ext_behavior behavior) const; +}; + +#define EXT(NAME, VS, GS, FS, GL, ES, SUPPORTED_FLAG) \ + { "GL_" #NAME, VS, GS, FS, GL, ES, &gl_extensions::SUPPORTED_FLAG, \ + &_mesa_glsl_parse_state::NAME##_enable, \ + &_mesa_glsl_parse_state::NAME##_warn } + +/** + * Table of extensions that can be enabled/disabled within a shader, + * and the conditions under which they are supported. + */ +static const _mesa_glsl_extension _mesa_glsl_supported_extensions[] = { + /* target availability API availability */ + /* name VS GS FS GL ES supported flag */ + EXT(ARB_conservative_depth, false, false, true, true, false, ARB_conservative_depth), + EXT(ARB_draw_buffers, false, false, true, true, false, dummy_true), + EXT(ARB_draw_instanced, true, false, false, true, false, ARB_draw_instanced), + EXT(ARB_explicit_attrib_location, true, false, true, true, false, ARB_explicit_attrib_location), + EXT(ARB_fragment_coord_conventions, true, false, true, true, false, ARB_fragment_coord_conventions), + EXT(ARB_texture_rectangle, true, false, true, true, false, dummy_true), + EXT(EXT_texture_array, true, false, true, true, false, EXT_texture_array), + EXT(ARB_shader_texture_lod, true, false, true, true, false, ARB_shader_texture_lod), + EXT(ARB_shader_stencil_export, false, false, true, true, false, ARB_shader_stencil_export), + EXT(AMD_conservative_depth, false, false, true, true, false, ARB_conservative_depth), + EXT(AMD_shader_stencil_export, false, false, true, true, false, ARB_shader_stencil_export), + EXT(OES_texture_3D, true, false, true, false, true, EXT_texture3D), + EXT(OES_EGL_image_external, true, false, true, false, true, OES_EGL_image_external), +}; + +#undef EXT + + +/** + * Determine whether a given extension is compatible with the target, + * API, and extension information in the current parser state. + */ +bool _mesa_glsl_extension::compatible_with_state(const _mesa_glsl_parse_state * + state) const +{ + /* Check that this extension matches the type of shader we are + * compiling to. + */ + switch (state->target) { + case vertex_shader: + if (!this->avail_in_VS) { + return false; + } + break; + case geometry_shader: + if (!this->avail_in_GS) { + return false; + } + break; + case fragment_shader: + if (!this->avail_in_FS) { + return false; + } + break; + default: + assert (!"Unrecognized shader target"); + return false; + } + + /* Check that this extension matches whether we are compiling + * for desktop GL or GLES. + */ + if (state->es_shader) { + if (!this->avail_in_ES) return false; + } else { + if (!this->avail_in_GL) return false; + } + + /* Check that this extension is supported by the OpenGL + * implementation. + * + * Note: the ->* operator indexes into state->extensions by the + * offset this->supported_flag. See + * _mesa_glsl_extension::supported_flag for more info. + */ + return state->extensions->*(this->supported_flag); +} + +/** + * Set the appropriate flags in the parser state to establish the + * given behavior for this extension. + */ +void _mesa_glsl_extension::set_flags(_mesa_glsl_parse_state *state, + ext_behavior behavior) const +{ + /* Note: the ->* operator indexes into state by the + * offsets this->enable_flag and this->warn_flag. See + * _mesa_glsl_extension::supported_flag for more info. + */ + state->*(this->enable_flag) = (behavior != extension_disable); + state->*(this->warn_flag) = (behavior == extension_warn); +} + +/** + * Find an extension by name in _mesa_glsl_supported_extensions. If + * the name is not found, return NULL. + */ +static const _mesa_glsl_extension *find_extension(const char *name) +{ + for (unsigned i = 0; i < Elements(_mesa_glsl_supported_extensions); ++i) { + if (strcmp(name, _mesa_glsl_supported_extensions[i].name) == 0) { + return &_mesa_glsl_supported_extensions[i]; + } + } + return NULL; +} + + bool _mesa_glsl_process_extension(const char *name, YYLTYPE *name_locp, - const char *behavior, YYLTYPE *behavior_locp, + const char *behavior_string, YYLTYPE *behavior_locp, _mesa_glsl_parse_state *state) { - enum { - extension_disable, - extension_enable, - extension_require, - extension_warn - } ext_mode; - - if (strcmp(behavior, "warn") == 0) { - ext_mode = extension_warn; - } else if (strcmp(behavior, "require") == 0) { - ext_mode = extension_require; - } else if (strcmp(behavior, "enable") == 0) { - ext_mode = extension_enable; - } else if (strcmp(behavior, "disable") == 0) { - ext_mode = extension_disable; + ext_behavior behavior; + if (strcmp(behavior_string, "warn") == 0) { + behavior = extension_warn; + } else if (strcmp(behavior_string, "require") == 0) { + behavior = extension_require; + } else if (strcmp(behavior_string, "enable") == 0) { + behavior = extension_enable; + } else if (strcmp(behavior_string, "disable") == 0) { + behavior = extension_disable; } else { _mesa_glsl_error(behavior_locp, state, "Unknown extension behavior `%s'", - behavior); + behavior_string); return false; } - bool unsupported = false; - if (strcmp(name, "all") == 0) { - if ((ext_mode == extension_enable) || (ext_mode == extension_require)) { + if ((behavior == extension_enable) || (behavior == extension_require)) { _mesa_glsl_error(name_locp, state, "Cannot %s all extensions", - (ext_mode == extension_enable) + (behavior == extension_enable) ? "enable" : "require"); return false; - } - } else if (strcmp(name, "GL_ARB_draw_buffers") == 0) { - /* This extension is only supported in fragment shaders. - */ - if (state->target != fragment_shader) { - unsupported = true; } else { - state->ARB_draw_buffers_enable = (ext_mode != extension_disable); - state->ARB_draw_buffers_warn = (ext_mode == extension_warn); + for (unsigned i = 0; + i < Elements(_mesa_glsl_supported_extensions); ++i) { + const _mesa_glsl_extension *extension + = &_mesa_glsl_supported_extensions[i]; + if (extension->compatible_with_state(state)) { + _mesa_glsl_supported_extensions[i].set_flags(state, behavior); + } + } } - } else if (strcmp(name, "GL_ARB_draw_instanced") == 0) { - /* This extension is only supported in vertex shaders. - */ - if (state->target != vertex_shader) { - unsupported = true; - } else { - state->ARB_draw_instanced_enable = (ext_mode != extension_disable); - state->ARB_draw_instanced_warn = (ext_mode == extension_warn); - } - } else if (strcmp(name, "GL_ARB_explicit_attrib_location") == 0) { - state->ARB_explicit_attrib_location_enable = - (ext_mode != extension_disable); - state->ARB_explicit_attrib_location_warn = - (ext_mode == extension_warn); - - unsupported = !state->extensions->ARB_explicit_attrib_location; - } else if (strcmp(name, "GL_ARB_fragment_coord_conventions") == 0) { - state->ARB_fragment_coord_conventions_enable = - (ext_mode != extension_disable); - state->ARB_fragment_coord_conventions_warn = - (ext_mode == extension_warn); - - unsupported = !state->extensions->ARB_fragment_coord_conventions; - } else if (strcmp(name, "GL_ARB_texture_rectangle") == 0) { - state->ARB_texture_rectangle_enable = (ext_mode != extension_disable); - state->ARB_texture_rectangle_warn = (ext_mode == extension_warn); - } else if (strcmp(name, "GL_EXT_texture_array") == 0) { - state->EXT_texture_array_enable = (ext_mode != extension_disable); - state->EXT_texture_array_warn = (ext_mode == extension_warn); - - unsupported = !state->extensions->EXT_texture_array; - } else if (strcmp(name, "GL_ARB_shader_stencil_export") == 0) { - if (state->target != fragment_shader) { - unsupported = true; - } else { - state->ARB_shader_stencil_export_enable = (ext_mode != extension_disable); - state->ARB_shader_stencil_export_warn = (ext_mode == extension_warn); - unsupported = !state->extensions->ARB_shader_stencil_export; - } - } else if (strcmp(name, "GL_AMD_conservative_depth") == 0) { - /* The AMD_conservative spec does not forbid requiring the extension in - * the vertex shader. - */ - state->AMD_conservative_depth_enable = (ext_mode != extension_disable); - state->AMD_conservative_depth_warn = (ext_mode == extension_warn); - unsupported = !state->extensions->AMD_conservative_depth; } else { - unsupported = true; - } - - if (unsupported) { - static const char *const fmt = "extension `%s' unsupported in %s shader"; - - if (ext_mode == extension_require) { - _mesa_glsl_error(name_locp, state, fmt, - name, _mesa_glsl_shader_target_name(state->target)); - return false; + const _mesa_glsl_extension *extension = find_extension(name); + if (extension && extension->compatible_with_state(state)) { + extension->set_flags(state, behavior); } else { - _mesa_glsl_warning(name_locp, state, fmt, - name, _mesa_glsl_shader_target_name(state->target)); + static const char *const fmt = "extension `%s' unsupported in %s shader"; + + if (behavior == extension_require) { + _mesa_glsl_error(name_locp, state, fmt, + name, _mesa_glsl_shader_target_name(state->target)); + return false; + } else { + _mesa_glsl_warning(name_locp, state, fmt, + name, _mesa_glsl_shader_target_name(state->target)); + } } } @@ -414,7 +555,7 @@ ast_expression::print(void) const printf("? "); subexpressions[1]->print(); printf(": "); - subexpressions[1]->print(); + subexpressions[2]->print(); break; case ast_array_index: @@ -490,6 +631,7 @@ ast_expression::ast_expression(int oper, this->subexpressions[0] = ex0; this->subexpressions[1] = ex1; this->subexpressions[2] = ex2; + this->non_lvalue_description = NULL; } @@ -571,7 +713,7 @@ ast_declaration::print(void) const } -ast_declaration::ast_declaration(char *identifier, int is_array, +ast_declaration::ast_declaration(const char *identifier, int is_array, ast_expression *array_size, ast_expression *initializer) { @@ -670,6 +812,106 @@ ast_selection_statement::ast_selection_statement(ast_expression *condition, } +void +ast_switch_statement::print(void) const +{ + printf("switch ( "); + test_expression->print(); + printf(") "); + + body->print(); +} + + +ast_switch_statement::ast_switch_statement(ast_expression *test_expression, + ast_node *body) +{ + this->test_expression = test_expression; + this->body = body; +} + + +void +ast_switch_body::print(void) const +{ + printf("{\n"); + if (stmts != NULL) { + stmts->print(); + } + printf("}\n"); +} + + +ast_switch_body::ast_switch_body(ast_case_statement_list *stmts) +{ + this->stmts = stmts; +} + + +void ast_case_label::print(void) const +{ + if (test_value != NULL) { + printf("case "); + test_value->print(); + printf(": "); + } else { + printf("default: "); + } +} + + +ast_case_label::ast_case_label(ast_expression *test_value) +{ + this->test_value = test_value; +} + + +void ast_case_label_list::print(void) const +{ + foreach_list_const(n, & this->labels) { + ast_node *ast = exec_node_data(ast_node, n, link); + ast->print(); + } + printf("\n"); +} + + +ast_case_label_list::ast_case_label_list(void) +{ +} + + +void ast_case_statement::print(void) const +{ + labels->print(); + foreach_list_const(n, & this->stmts) { + ast_node *ast = exec_node_data(ast_node, n, link); + ast->print(); + printf("\n"); + } +} + + +ast_case_statement::ast_case_statement(ast_case_label_list *labels) +{ + this->labels = labels; +} + + +void ast_case_statement_list::print(void) const +{ + foreach_list_const(n, & this->cases) { + ast_node *ast = exec_node_data(ast_node, n, link); + ast->print(); + } +} + + +ast_case_statement_list::ast_case_statement_list(void) +{ +} + + void ast_iteration_statement::print(void) const { @@ -737,7 +979,7 @@ ast_struct_specifier::print(void) const } -ast_struct_specifier::ast_struct_specifier(char *identifier, +ast_struct_specifier::ast_struct_specifier(const char *identifier, ast_node *declarator_list) { if (identifier == NULL) { @@ -749,8 +991,27 @@ ast_struct_specifier::ast_struct_specifier(char *identifier, this->declarations.push_degenerate_list_at_head(&declarator_list->link); } +/** + * Do the set of common optimizations passes + * + * \param ir List of instructions to be optimized + * \param linked Is the shader linked? This enables + * optimizations passes that remove code at + * global scope and could cause linking to + * fail. + * \param uniform_locations_assigned Have locations already been assigned for + * uniforms? This prevents the declarations + * of unused uniforms from being removed. + * The setting of this flag only matters if + * \c linked is \c true. + * \param max_unroll_iterations Maximum number of loop iterations to be + * unrolled. Setting to 0 forces all loops + * to be unrolled. + */ bool -do_common_optimization(exec_list *ir, bool linked, unsigned max_unroll_iterations) +do_common_optimization(exec_list *ir, bool linked, + bool uniform_locations_assigned, + unsigned max_unroll_iterations) { GLboolean progress = GL_FALSE; @@ -759,13 +1020,14 @@ do_common_optimization(exec_list *ir, bool linked, unsigned max_unroll_iteration if (linked) { progress = do_function_inlining(ir) || progress; progress = do_dead_functions(ir) || progress; + progress = do_structure_splitting(ir) || progress; } - progress = do_structure_splitting(ir) || progress; progress = do_if_simplification(ir) || progress; progress = do_discard_simplification(ir) || progress; progress = do_copy_propagation(ir) || progress; + progress = do_copy_propagation_elements(ir) || progress; if (linked) - progress = do_dead_code(ir) || progress; + progress = do_dead_code(ir, uniform_locations_assigned) || progress; else progress = do_dead_code_unlinked(ir) || progress; progress = do_dead_code_local(ir) || progress; @@ -782,6 +1044,7 @@ do_common_optimization(exec_list *ir, bool linked, unsigned max_unroll_iteration progress = do_swizzle_swizzle(ir) || progress; progress = do_noop_swizzle(ir) || progress; + progress = optimize_split_arrays(ir, linked) || progress; progress = optimize_redundant_jumps(ir) || progress; loop_state *ls = analyze_loop_variables(ir);