From 29285882676388aacff123e8bdf025904abf8ea9 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Thu, 24 Jun 2010 15:32:15 -0700 Subject: glsl2: Move the compiler to the subdirectory it will live in in Mesa. --- src/glsl/main.cpp | 256 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 256 insertions(+) create mode 100644 src/glsl/main.cpp (limited to 'src/glsl/main.cpp') diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp new file mode 100644 index 0000000000..dcd9bd69c0 --- /dev/null +++ b/src/glsl/main.cpp @@ -0,0 +1,256 @@ +/* + * Copyright © 2008, 2009 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +#include +#include +#include + +#include +#include +#include +#include + +#include "ast.h" +#include "glsl_parser_extras.h" +#include "glsl_parser.h" +#include "ir_optimization.h" +#include "ir_print_visitor.h" +#include "program.h" + +/* Returned string will have 'ctx' as its talloc owner. */ +static char * +load_text_file(void *ctx, const char *file_name, size_t *size) +{ + char *text = NULL; + struct stat st; + ssize_t total_read = 0; + int fd = open(file_name, O_RDONLY); + + *size = 0; + if (fd < 0) { + return NULL; + } + + if (fstat(fd, & st) == 0) { + text = (char *) talloc_size(ctx, st.st_size + 1); + if (text != NULL) { + do { + ssize_t bytes = read(fd, text + total_read, + st.st_size - total_read); + if (bytes < 0) { + free(text); + text = NULL; + break; + } + + if (bytes == 0) { + break; + } + + total_read += bytes; + } while (total_read < st.st_size); + + text[total_read] = '\0'; + *size = total_read; + } + } + + close(fd); + + return text; +} + + +void +usage_fail(const char *name) +{ + printf("%s \n", name); + exit(EXIT_FAILURE); +} + + +int dump_ast = 0; +int dump_lir = 0; +int do_link = 0; + +const struct option compiler_opts[] = { + { "dump-ast", 0, &dump_ast, 1 }, + { "dump-lir", 0, &dump_lir, 1 }, + { "link", 0, &do_link, 1 }, + { NULL, 0, NULL, 0 } +}; + +void +compile_shader(struct glsl_shader *shader) +{ + struct _mesa_glsl_parse_state *state; + + state = talloc_zero(talloc_parent(shader), struct _mesa_glsl_parse_state); + + switch (shader->Type) { + case GL_VERTEX_SHADER: state->target = vertex_shader; break; + case GL_FRAGMENT_SHADER: state->target = fragment_shader; break; + case GL_GEOMETRY_SHADER: state->target = geometry_shader; break; + } + + state->scanner = NULL; + state->translation_unit.make_empty(); + state->symbols = new(shader) glsl_symbol_table; + state->info_log = talloc_strdup(shader, ""); + state->error = false; + state->temp_index = 0; + state->loop_or_switch_nesting = NULL; + state->ARB_texture_rectangle_enable = true; + + /* Create a new context for the preprocessor output. Ultimately, this + * should probably be the parser context, but there isn't one yet. + */ + const char *source = shader->Source; + state->error = preprocess(shader, &source, &state->info_log); + + if (!state->error) { + _mesa_glsl_lexer_ctor(state, source); + _mesa_glsl_parse(state); + _mesa_glsl_lexer_dtor(state); + } + + if (dump_ast) { + foreach_list_const(n, &state->translation_unit) { + ast_node *ast = exec_node_data(ast_node, n, link); + ast->print(); + } + printf("\n\n"); + } + + shader->ir.make_empty(); + if (!state->error && !state->translation_unit.is_empty()) + _mesa_ast_to_hir(&shader->ir, state); + + validate_ir_tree(&shader->ir); + + /* Optimization passes */ + if (!state->error && !shader->ir.is_empty()) { + bool progress; + do { + progress = false; + + progress = do_function_inlining(&shader->ir) || progress; + progress = do_if_simplification(&shader->ir) || progress; + progress = do_copy_propagation(&shader->ir) || progress; + progress = do_dead_code_local(&shader->ir) || progress; + progress = do_dead_code_unlinked(&shader->ir) || progress; + progress = do_constant_variable_unlinked(&shader->ir) || progress; + progress = do_constant_folding(&shader->ir) || progress; + progress = do_vec_index_to_swizzle(&shader->ir) || progress; + progress = do_swizzle_swizzle(&shader->ir) || progress; + } while (progress); + } + + validate_ir_tree(&shader->ir); + + /* Print out the resulting IR */ + if (!state->error && dump_lir) { + _mesa_print_ir(&shader->ir, state); + } + + shader->symbols = state->symbols; + shader->CompileStatus = !state->error; + + if (shader->InfoLog) + talloc_free(shader->InfoLog); + + shader->InfoLog = state->info_log; + + talloc_free(state); + + return; +} + +int +main(int argc, char **argv) +{ + int status = EXIT_SUCCESS; + + int c; + int idx = 0; + while ((c = getopt_long(argc, argv, "", compiler_opts, &idx)) != -1) + /* empty */ ; + + + if (argc <= optind) + usage_fail(argv[0]); + + struct glsl_program *whole_program; + + whole_program = talloc_zero (NULL, struct glsl_program); + assert(whole_program != NULL); + + for (/* empty */; argc > optind; optind++) { + whole_program->Shaders = (struct glsl_shader **) + talloc_realloc(whole_program, whole_program->Shaders, + struct glsl_shader *, whole_program->NumShaders + 1); + assert(whole_program->Shaders != NULL); + + struct glsl_shader *shader = talloc_zero(whole_program, glsl_shader); + + whole_program->Shaders[whole_program->NumShaders] = shader; + whole_program->NumShaders++; + + const unsigned len = strlen(argv[optind]); + if (len < 6) + usage_fail(argv[0]); + + const char *const ext = & argv[optind][len - 5]; + if (strncmp(".vert", ext, 5) == 0) + shader->Type = GL_VERTEX_SHADER; + else if (strncmp(".geom", ext, 5) == 0) + shader->Type = GL_GEOMETRY_SHADER; + else if (strncmp(".frag", ext, 5) == 0) + shader->Type = GL_FRAGMENT_SHADER; + else + usage_fail(argv[0]); + + shader->Source = load_text_file(whole_program, + argv[optind], &shader->SourceLen); + if (shader->Source == NULL) { + printf("File \"%s\" does not exist.\n", argv[optind]); + exit(EXIT_FAILURE); + } + + compile_shader(shader); + + if (!shader->CompileStatus) { + printf("Info log for %s:\n%s\n", argv[optind], shader->InfoLog); + status = EXIT_FAILURE; + break; + } + } + + if ((status == EXIT_SUCCESS) && do_link) { + link_shaders(whole_program); + status = (whole_program->LinkStatus) ? EXIT_SUCCESS : EXIT_FAILURE; + } + + talloc_free(whole_program); + + return status; +} -- cgit v1.2.3 From bda27424cf04c0d2ec2b49c56f562d5b2d2f0bff Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 25 Jun 2010 13:38:38 -0700 Subject: glsl2: Use the parser state as the talloc context for dead code elimination. This cuts runtime by around 20% from talloc_parent() lookups. --- src/glsl/ir_dead_code.cpp | 15 +++++++++------ src/glsl/ir_optimization.h | 6 ++++-- src/glsl/main.cpp | 2 +- src/mesa/shader/ir_to_mesa.cpp | 2 +- 4 files changed, 15 insertions(+), 10 deletions(-) (limited to 'src/glsl/main.cpp') diff --git a/src/glsl/ir_dead_code.cpp b/src/glsl/ir_dead_code.cpp index 8821304682..51fa96df0c 100644 --- a/src/glsl/ir_dead_code.cpp +++ b/src/glsl/ir_dead_code.cpp @@ -71,6 +71,8 @@ public: /* List of variable_entry */ exec_list variable_list; + + void *mem_ctx; }; @@ -84,9 +86,7 @@ ir_dead_code_visitor::get_variable_entry(ir_variable *var) return entry; } - void *ctx = talloc_parent(var); - - variable_entry *entry = new(ctx) variable_entry(var); + variable_entry *entry = new(mem_ctx) variable_entry(var); this->variable_list.push_tail(entry); return entry; } @@ -147,11 +147,13 @@ ir_dead_code_visitor::visit_leave(ir_assignment *ir) * for usage on an unlinked instruction stream. */ bool -do_dead_code(exec_list *instructions) +do_dead_code(struct _mesa_glsl_parse_state *state, + exec_list *instructions) { ir_dead_code_visitor v; bool progress = false; + v.mem_ctx = state; v.run(instructions); foreach_iter(exec_list_iterator, iter, v.variable_list) { @@ -198,7 +200,8 @@ do_dead_code(exec_list *instructions) * with global scope. */ bool -do_dead_code_unlinked(exec_list *instructions) +do_dead_code_unlinked(struct _mesa_glsl_parse_state *state, + exec_list *instructions) { bool progress = false; @@ -209,7 +212,7 @@ do_dead_code_unlinked(exec_list *instructions) foreach_iter(exec_list_iterator, sigiter, *f) { ir_function_signature *sig = (ir_function_signature *) sigiter.get(); - if (do_dead_code(&sig->body)) + if (do_dead_code(state, &sig->body)) progress = true; } } diff --git a/src/glsl/ir_optimization.h b/src/glsl/ir_optimization.h index 432a33458c..147f92176b 100644 --- a/src/glsl/ir_optimization.h +++ b/src/glsl/ir_optimization.h @@ -32,9 +32,11 @@ bool do_constant_folding(exec_list *instructions); bool do_constant_variable(exec_list *instructions); bool do_constant_variable_unlinked(exec_list *instructions); bool do_copy_propagation(exec_list *instructions); -bool do_dead_code(exec_list *instructions); +bool do_dead_code(struct _mesa_glsl_parse_state *state, + exec_list *instructions); bool do_dead_code_local(exec_list *instructions); -bool do_dead_code_unlinked(exec_list *instructions); +bool do_dead_code_unlinked(struct _mesa_glsl_parse_state *state, + exec_list *instructions); bool do_function_inlining(exec_list *instructions); bool do_if_simplification(exec_list *instructions); bool do_swizzle_swizzle(exec_list *instructions); diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp index dcd9bd69c0..b32e2ad3db 100644 --- a/src/glsl/main.cpp +++ b/src/glsl/main.cpp @@ -157,7 +157,7 @@ compile_shader(struct glsl_shader *shader) progress = do_if_simplification(&shader->ir) || progress; progress = do_copy_propagation(&shader->ir) || progress; progress = do_dead_code_local(&shader->ir) || progress; - progress = do_dead_code_unlinked(&shader->ir) || progress; + progress = do_dead_code_unlinked(state, &shader->ir) || progress; progress = do_constant_variable_unlinked(&shader->ir) || progress; progress = do_constant_folding(&shader->ir) || progress; progress = do_vec_index_to_swizzle(&shader->ir) || progress; diff --git a/src/mesa/shader/ir_to_mesa.cpp b/src/mesa/shader/ir_to_mesa.cpp index f58af0f65f..0425e7d91e 100644 --- a/src/mesa/shader/ir_to_mesa.cpp +++ b/src/mesa/shader/ir_to_mesa.cpp @@ -1332,7 +1332,7 @@ _mesa_get_glsl_shader(GLcontext *ctx, void *mem_ctx, struct gl_shader *sh) progress = do_if_simplification(&shader->ir) || progress; progress = do_copy_propagation(&shader->ir) || progress; progress = do_dead_code_local(&shader->ir) || progress; - progress = do_dead_code_unlinked(&shader->ir) || progress; + progress = do_dead_code_unlinked(state, &shader->ir) || progress; progress = do_constant_variable_unlinked(&shader->ir) || progress; progress = do_constant_folding(&shader->ir) || progress; progress = do_vec_index_to_swizzle(&shader->ir) || progress; -- cgit v1.2.3 From 22c23dedad4e7f362ffbd990f1c2d5caf4cae75a Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Fri, 25 Jun 2010 15:27:47 -0700 Subject: glsl2: Add option to stand-alone GLSL compiler to dump IR before optimizations --- src/glsl/main.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/glsl/main.cpp') diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp index b32e2ad3db..16b2cf84c5 100644 --- a/src/glsl/main.cpp +++ b/src/glsl/main.cpp @@ -89,11 +89,13 @@ usage_fail(const char *name) int dump_ast = 0; +int dump_hir = 0; int dump_lir = 0; int do_link = 0; const struct option compiler_opts[] = { { "dump-ast", 0, &dump_ast, 1 }, + { "dump-hir", 0, &dump_hir, 1 }, { "dump-lir", 0, &dump_lir, 1 }, { "link", 0, &do_link, 1 }, { NULL, 0, NULL, 0 } @@ -147,6 +149,11 @@ compile_shader(struct glsl_shader *shader) validate_ir_tree(&shader->ir); + /* Print out the unoptimized IR. */ + if (!state->error && dump_hir) { + _mesa_print_ir(&shader->ir, state); + } + /* Optimization passes */ if (!state->error && !shader->ir.is_empty()) { bool progress; -- cgit v1.2.3 From efc15f862b08a9f035c06a79bc43848cca740372 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Mon, 28 Jun 2010 13:17:18 -0700 Subject: glsl_type: Add _mesa_glsl_release_types to release all type related storage --- src/glsl/glsl_types.cpp | 20 ++++++++++++++++++++ src/glsl/glsl_types.h | 14 ++++++++++++-- src/glsl/main.cpp | 1 + 3 files changed, 33 insertions(+), 2 deletions(-) (limited to 'src/glsl/main.cpp') diff --git a/src/glsl/glsl_types.cpp b/src/glsl/glsl_types.cpp index 0d807fbc3d..806b71495d 100644 --- a/src/glsl/glsl_types.cpp +++ b/src/glsl/glsl_types.cpp @@ -195,6 +195,26 @@ const glsl_type *glsl_type::get_base_type() const } +void +_mesa_glsl_release_types(void) +{ + if (glsl_type::array_types != NULL) { + hash_table_dtor(glsl_type::array_types); + glsl_type::array_types = NULL; + } + + if (glsl_type::record_types != NULL) { + hash_table_dtor(glsl_type::record_types); + glsl_type::record_types = NULL; + } + + if (glsl_type::ctx != NULL) { + talloc_free(glsl_type::ctx); + glsl_type::ctx = NULL; + } +} + + ir_function * glsl_type::generate_constructor(glsl_symbol_table *symtab) const { diff --git a/src/glsl/glsl_types.h b/src/glsl/glsl_types.h index 1147d38ca6..e869071cab 100644 --- a/src/glsl/glsl_types.h +++ b/src/glsl/glsl_types.h @@ -39,6 +39,9 @@ struct _mesa_glsl_parse_state; extern "C" void _mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *state); +extern "C" void +_mesa_glsl_release_types(void); + #define GLSL_TYPE_UINT 0 #define GLSL_TYPE_INT 1 #define GLSL_TYPE_FLOAT 2 @@ -455,11 +458,18 @@ private: bool); static void generate_EXT_texture_array_types(class glsl_symbol_table *, bool); + /*@}*/ + /** - * This function is a friend because it needs to call the various - * generate_*_types functions and it has C linkage. + * \name Friend functions. + * + * These functions are friends because they must have C linkage and the + * need to call various private methods or access various private static + * data. */ + /*@{*/ friend void _mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *); + friend void _mesa_glsl_release_types(void); /*@}*/ }; diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp index 16b2cf84c5..342cf98840 100644 --- a/src/glsl/main.cpp +++ b/src/glsl/main.cpp @@ -258,6 +258,7 @@ main(int argc, char **argv) } talloc_free(whole_program); + _mesa_glsl_release_types(); return status; } -- cgit v1.2.3 From 5e18b051c039564d1998818d08caf1bff3983630 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Tue, 29 Jun 2010 14:21:05 -0700 Subject: glsl2: Pass MaxDrawBuffers from core Mesa into the GLSL compiler --- src/glsl/glsl_parser_extras.h | 9 +++++++++ src/glsl/ir_variable.cpp | 46 ++++++++++++++++++++---------------------- src/glsl/main.cpp | 2 ++ src/mesa/shader/ir_to_mesa.cpp | 2 ++ 4 files changed, 35 insertions(+), 24 deletions(-) (limited to 'src/glsl/main.cpp') diff --git a/src/glsl/glsl_parser_extras.h b/src/glsl/glsl_parser_extras.h index 726bafa7e4..f957a926be 100644 --- a/src/glsl/glsl_parser_extras.h +++ b/src/glsl/glsl_parser_extras.h @@ -43,6 +43,15 @@ struct _mesa_glsl_parse_state { unsigned language_version; enum _mesa_glsl_parser_targets target; + /** + * Implementation defined limits that affect built-in variables, etc. + * + * \sa struct gl_constants (in mtypes.h) + */ + struct { + unsigned MaxDrawBuffers; + } Const; + /** * During AST to IR conversion, pointer to current IR function * diff --git a/src/glsl/ir_variable.cpp b/src/glsl/ir_variable.cpp index 15a4a92f62..44c3065107 100644 --- a/src/glsl/ir_variable.cpp +++ b/src/glsl/ir_variable.cpp @@ -221,20 +221,20 @@ initialize_vs_variables(exec_list *instructions, static void generate_110_fs_variables(exec_list *instructions, - glsl_symbol_table *symtab) + struct _mesa_glsl_parse_state *state) { for (unsigned i = 0; i < Elements(builtin_core_fs_variables); i++) { add_builtin_variable(& builtin_core_fs_variables[i], - instructions, symtab); + instructions, state->symbols); } for (unsigned i = 0 ; i < Elements(builtin_110_deprecated_fs_variables) ; i++) { add_builtin_variable(& builtin_110_deprecated_fs_variables[i], - instructions, symtab); + instructions, state->symbols); } - generate_110_uniforms(instructions, symtab); + generate_110_uniforms(instructions, state->symbols); /* FINISHME: The size of this array is implementation dependent based on the * FINISHME: value of GL_MAX_TEXTURE_COORDS. Every platform that supports @@ -242,27 +242,25 @@ generate_110_fs_variables(exec_list *instructions, * FINISHME: for now. */ const glsl_type *const vec4_array_type = - glsl_type::get_array_instance(symtab, glsl_type::vec4_type, 4); + glsl_type::get_array_instance(state->symbols, glsl_type::vec4_type, 4); add_variable("gl_TexCoord", ir_var_in, FRAG_ATTRIB_TEX0, vec4_array_type, - instructions, symtab); + instructions, state->symbols); } static void generate_ARB_draw_buffers_fs_variables(exec_list *instructions, - glsl_symbol_table *symtab, bool warn) + struct _mesa_glsl_parse_state *state, + bool warn) { - /* FINISHME: The size of this array is implementation dependent based on the - * FINISHME: value of GL_MAX_DRAW_BUFFERS. GL_MAX_DRAW_BUFFERS must be - * FINISHME: at least 1, so hard-code 1 for now. - */ const glsl_type *const vec4_array_type = - glsl_type::get_array_instance(symtab, glsl_type::vec4_type, 1); + glsl_type::get_array_instance(state->symbols, glsl_type::vec4_type, + state->Const.MaxDrawBuffers); ir_variable *const fd = add_variable("gl_FragData", ir_var_out, FRAG_RESULT_DATA0, - vec4_array_type, instructions, symtab); + vec4_array_type, instructions, state->symbols); if (warn) fd->warn_extension = "GL_ARB_draw_buffers"; @@ -271,18 +269,18 @@ generate_ARB_draw_buffers_fs_variables(exec_list *instructions, static void generate_120_fs_variables(exec_list *instructions, - glsl_symbol_table *symtab) + struct _mesa_glsl_parse_state *state) { - generate_110_fs_variables(instructions, symtab); - generate_ARB_draw_buffers_fs_variables(instructions, symtab, false); + generate_110_fs_variables(instructions, state); + generate_ARB_draw_buffers_fs_variables(instructions, state, false); } static void generate_130_fs_variables(exec_list *instructions, - glsl_symbol_table *symtab) + struct _mesa_glsl_parse_state *state) { - void *ctx = symtab; - generate_120_fs_variables(instructions, symtab); + void *ctx = state->symbols; + generate_120_fs_variables(instructions, state); /* FINISHME: The size of this array is implementation dependent based on * FINISHME: the value of GL_MAX_CLIP_DISTANCES. @@ -292,7 +290,7 @@ generate_130_fs_variables(exec_list *instructions, /* FINISHME: gl_ClipDistance needs a real location assigned. */ add_variable("gl_ClipDistance", ir_var_in, -1, clip_distance_array_type, - instructions, symtab); + instructions, state->symbols); } static void @@ -302,13 +300,13 @@ initialize_fs_variables(exec_list *instructions, switch (state->language_version) { case 110: - generate_110_fs_variables(instructions, state->symbols); + generate_110_fs_variables(instructions, state); break; case 120: - generate_120_fs_variables(instructions, state->symbols); + generate_120_fs_variables(instructions, state); break; case 130: - generate_130_fs_variables(instructions, state->symbols); + generate_130_fs_variables(instructions, state); break; } @@ -318,7 +316,7 @@ initialize_fs_variables(exec_list *instructions, */ if (state->language_version < 120) { if (state->ARB_draw_buffers_enable) { - generate_ARB_draw_buffers_fs_variables(instructions, state->symbols, + generate_ARB_draw_buffers_fs_variables(instructions, state, state->ARB_draw_buffers_warn); } } diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp index 342cf98840..f1dab7b576 100644 --- a/src/glsl/main.cpp +++ b/src/glsl/main.cpp @@ -123,6 +123,8 @@ compile_shader(struct glsl_shader *shader) state->loop_or_switch_nesting = NULL; state->ARB_texture_rectangle_enable = true; + state->Const.MaxDrawBuffers = 2; + /* Create a new context for the preprocessor output. Ultimately, this * should probably be the parser context, but there isn't one yet. */ diff --git a/src/mesa/shader/ir_to_mesa.cpp b/src/mesa/shader/ir_to_mesa.cpp index 1232bada27..ab8aca0a81 100644 --- a/src/mesa/shader/ir_to_mesa.cpp +++ b/src/mesa/shader/ir_to_mesa.cpp @@ -1526,6 +1526,8 @@ _mesa_get_glsl_shader(GLcontext *ctx, void *mem_ctx, struct gl_shader *sh) state->loop_or_switch_nesting = NULL; state->ARB_texture_rectangle_enable = true; + state->Const.MaxDrawBuffers = ctx->Const.MaxDrawBuffers; + /* Create a new context for the preprocessor output. Ultimately, this * should probably be the parser context, but there isn't one yet. */ -- cgit v1.2.3 From 16b68b1952d0da14b9ce8306efa64988ce46b4b7 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 30 Jun 2010 11:05:43 -0700 Subject: glsl2: Move our data from a glsl_shader* on the side to the main gl_shader *. This saves recompiling at link time. gl_shader->ir is made a pointer so that we don't have to bring exec_list into mtypes.h. --- src/glsl/linker.cpp | 48 +++++++++++++-------------- src/glsl/list.h | 19 +++++++++++ src/glsl/main.cpp | 47 +++++++++++++-------------- src/glsl/program.h | 22 ++----------- src/mesa/main/mtypes.h | 3 ++ src/mesa/shader/ir_to_mesa.cpp | 73 +++++++++++++----------------------------- src/mesa/shader/shader_api.c | 8 ++--- 7 files changed, 95 insertions(+), 125 deletions(-) (limited to 'src/glsl/main.cpp') diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp index 8547f74ce6..df71f21b54 100644 --- a/src/glsl/linker.cpp +++ b/src/glsl/linker.cpp @@ -128,10 +128,10 @@ linker_error_printf(glsl_program *prog, const char *fmt, ...) void -invalidate_variable_locations(glsl_shader *sh, enum ir_variable_mode mode, +invalidate_variable_locations(gl_shader *sh, enum ir_variable_mode mode, int generic_base) { - foreach_list(node, &sh->ir) { + foreach_list(node, sh->ir) { ir_variable *const var = ((ir_instruction *) node)->as_variable(); if ((var == NULL) || (var->mode != (unsigned) mode)) @@ -187,7 +187,7 @@ count_attribute_slots(const glsl_type *t) */ bool validate_vertex_shader_executable(struct glsl_program *prog, - struct glsl_shader *shader) + struct gl_shader *shader) { if (shader == NULL) return true; @@ -198,7 +198,7 @@ validate_vertex_shader_executable(struct glsl_program *prog, } find_assignment_visitor find("gl_Position"); - find.run(&shader->ir); + find.run(shader->ir); if (!find.variable_found()) { linker_error_printf(prog, "vertex shader does not write to `gl_Position'\n"); @@ -216,7 +216,7 @@ validate_vertex_shader_executable(struct glsl_program *prog, */ bool validate_fragment_shader_executable(struct glsl_program *prog, - struct glsl_shader *shader) + struct gl_shader *shader) { if (shader == NULL) return true; @@ -229,8 +229,8 @@ validate_fragment_shader_executable(struct glsl_program *prog, find_assignment_visitor frag_color("gl_FragColor"); find_assignment_visitor frag_data("gl_FragData"); - frag_color.run(&shader->ir); - frag_data.run(&shader->ir); + frag_color.run(shader->ir); + frag_data.run(shader->ir); if (!frag_color.variable_found() && !frag_data.variable_found()) { linker_error_printf(prog, "fragment shader does not write to " @@ -259,7 +259,7 @@ cross_validate_uniforms(struct glsl_program *prog) */ glsl_symbol_table uniforms; for (unsigned i = 0; i < prog->_NumLinkedShaders; i++) { - foreach_list(node, &prog->_LinkedShaders[i]->ir) { + foreach_list(node, prog->_LinkedShaders[i]->ir) { ir_variable *const var = ((ir_instruction *) node)->as_variable(); if ((var == NULL) || (var->mode != ir_var_uniform)) @@ -309,7 +309,7 @@ cross_validate_uniforms(struct glsl_program *prog) */ bool cross_validate_outputs_to_inputs(struct glsl_program *prog, - glsl_shader *producer, glsl_shader *consumer) + gl_shader *producer, gl_shader *consumer) { glsl_symbol_table parameters; /* FINISHME: Figure these out dynamically. */ @@ -318,7 +318,7 @@ cross_validate_outputs_to_inputs(struct glsl_program *prog, /* Find all shader outputs in the "producer" stage. */ - foreach_list(node, &producer->ir) { + foreach_list(node, producer->ir) { ir_variable *const var = ((ir_instruction *) node)->as_variable(); /* FINISHME: For geometry shaders, this should also look for inout @@ -335,7 +335,7 @@ cross_validate_outputs_to_inputs(struct glsl_program *prog, * matching outputs already in the symbol table must have the same type and * qualifiers. */ - foreach_list(node, &consumer->ir) { + foreach_list(node, consumer->ir) { ir_variable *const input = ((ir_instruction *) node)->as_variable(); /* FINISHME: For geometry shaders, this should also look for inout @@ -423,7 +423,7 @@ assign_uniform_locations(struct glsl_program *prog) for (unsigned i = 0; i < prog->_NumLinkedShaders; i++) { unsigned next_position = 0; - foreach_list(node, &prog->_LinkedShaders[i]->ir) { + foreach_list(node, prog->_LinkedShaders[i]->ir) { ir_variable *const var = ((ir_instruction *) node)->as_variable(); if ((var == NULL) || (var->mode != ir_var_uniform)) @@ -540,7 +540,7 @@ assign_attribute_locations(glsl_program *prog, unsigned max_attribute_index) unsigned used_locations = (max_attribute_index >= 32) ? ~0 : ~((1 << max_attribute_index) - 1); - glsl_shader *const sh = prog->_LinkedShaders[0]; + gl_shader *const sh = prog->_LinkedShaders[0]; assert(sh->Type == GL_VERTEX_SHADER); /* Operate in a total of four passes. @@ -644,7 +644,7 @@ assign_attribute_locations(glsl_program *prog, unsigned max_attribute_index) unsigned num_attr = 0; - foreach_list(node, &sh->ir) { + foreach_list(node, sh->ir) { ir_variable *const var = ((ir_instruction *) node)->as_variable(); if ((var == NULL) || (var->mode != ir_var_in)) @@ -694,7 +694,7 @@ assign_attribute_locations(glsl_program *prog, unsigned max_attribute_index) void -assign_varying_locations(glsl_shader *producer, glsl_shader *consumer) +assign_varying_locations(gl_shader *producer, gl_shader *consumer) { /* FINISHME: Set dynamically when geometry shader support is added. */ unsigned output_index = VERT_RESULT_VAR0; @@ -714,7 +714,7 @@ assign_varying_locations(glsl_shader *producer, glsl_shader *consumer) invalidate_variable_locations(producer, ir_var_out, VERT_RESULT_VAR0); invalidate_variable_locations(consumer, ir_var_in, FRAG_ATTRIB_VAR0); - foreach_list(node, &producer->ir) { + foreach_list(node, producer->ir) { ir_variable *const output_var = ((ir_instruction *) node)->as_variable(); if ((output_var == NULL) || (output_var->mode != ir_var_out) @@ -740,7 +740,7 @@ assign_varying_locations(glsl_shader *producer, glsl_shader *consumer) input_index++; } - foreach_list(node, &producer->ir) { + foreach_list(node, producer->ir) { ir_variable *const var = ((ir_instruction *) node)->as_variable(); if ((var == NULL) || (var->mode != ir_var_out)) @@ -752,7 +752,7 @@ assign_varying_locations(glsl_shader *producer, glsl_shader *consumer) var->shader_out = (var->location != -1); } - foreach_list(node, &consumer->ir) { + foreach_list(node, consumer->ir) { ir_variable *const var = ((ir_instruction *) node)->as_variable(); if ((var == NULL) || (var->mode != ir_var_in)) @@ -780,13 +780,13 @@ link_shaders(struct glsl_program *prog) /* Separate the shaders into groups based on their type. */ - struct glsl_shader **vert_shader_list; + struct gl_shader **vert_shader_list; unsigned num_vert_shaders = 0; - struct glsl_shader **frag_shader_list; + struct gl_shader **frag_shader_list; unsigned num_frag_shaders = 0; - vert_shader_list = (struct glsl_shader **) - calloc(2 * prog->NumShaders, sizeof(struct glsl_shader *)); + vert_shader_list = (struct gl_shader **) + calloc(2 * prog->NumShaders, sizeof(struct gl_shader *)); frag_shader_list = &vert_shader_list[prog->NumShaders]; for (unsigned i = 0; i < prog->NumShaders; i++) { @@ -817,8 +817,8 @@ link_shaders(struct glsl_program *prog) goto done; - prog->_LinkedShaders = (struct glsl_shader **) - calloc(2, sizeof(struct glsl_shader *)); + prog->_LinkedShaders = (struct gl_shader **) + calloc(2, sizeof(struct gl_shader *)); prog->_NumLinkedShaders = 0; if (num_vert_shaders > 0) { diff --git a/src/glsl/list.h b/src/glsl/list.h index 7732d66d7a..d449bdd8b1 100644 --- a/src/glsl/list.h +++ b/src/glsl/list.h @@ -272,6 +272,25 @@ struct exec_list { struct exec_node *tail_pred; #ifdef __cplusplus + /* Callers of this talloc-based new need not call delete. It's + * easier to just talloc_free 'ctx' (or any of its ancestors). */ + static void* operator new(size_t size, void *ctx) + { + void *node; + + node = talloc_size(ctx, size); + assert(node != NULL); + + return node; + } + + /* If the user *does* call delete, that's OK, we will just + * talloc_free in that case. */ + static void operator delete(void *node) + { + talloc_free(node); + } + exec_list() { make_empty(); diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp index f1dab7b576..e78af42ac6 100644 --- a/src/glsl/main.cpp +++ b/src/glsl/main.cpp @@ -38,14 +38,13 @@ /* Returned string will have 'ctx' as its talloc owner. */ static char * -load_text_file(void *ctx, const char *file_name, size_t *size) +load_text_file(void *ctx, const char *file_name) { char *text = NULL; struct stat st; ssize_t total_read = 0; int fd = open(file_name, O_RDONLY); - *size = 0; if (fd < 0) { return NULL; } @@ -70,7 +69,6 @@ load_text_file(void *ctx, const char *file_name, size_t *size) } while (total_read < st.st_size); text[total_read] = '\0'; - *size = total_read; } } @@ -102,7 +100,7 @@ const struct option compiler_opts[] = { }; void -compile_shader(struct glsl_shader *shader) +compile_shader(struct gl_shader *shader) { struct _mesa_glsl_parse_state *state; @@ -145,40 +143,40 @@ compile_shader(struct glsl_shader *shader) printf("\n\n"); } - shader->ir.make_empty(); + shader->ir = new(shader) exec_list; if (!state->error && !state->translation_unit.is_empty()) - _mesa_ast_to_hir(&shader->ir, state); + _mesa_ast_to_hir(shader->ir, state); - validate_ir_tree(&shader->ir); + validate_ir_tree(shader->ir); /* Print out the unoptimized IR. */ if (!state->error && dump_hir) { - _mesa_print_ir(&shader->ir, state); + _mesa_print_ir(shader->ir, state); } /* Optimization passes */ - if (!state->error && !shader->ir.is_empty()) { + if (!state->error && !shader->ir->is_empty()) { bool progress; do { progress = false; - progress = do_function_inlining(&shader->ir) || progress; - progress = do_if_simplification(&shader->ir) || progress; - progress = do_copy_propagation(&shader->ir) || progress; - progress = do_dead_code_local(&shader->ir) || progress; - progress = do_dead_code_unlinked(state, &shader->ir) || progress; - progress = do_constant_variable_unlinked(&shader->ir) || progress; - progress = do_constant_folding(&shader->ir) || progress; - progress = do_vec_index_to_swizzle(&shader->ir) || progress; - progress = do_swizzle_swizzle(&shader->ir) || progress; + progress = do_function_inlining(shader->ir) || progress; + progress = do_if_simplification(shader->ir) || progress; + progress = do_copy_propagation(shader->ir) || progress; + progress = do_dead_code_local(shader->ir) || progress; + progress = do_dead_code_unlinked(state, shader->ir) || progress; + progress = do_constant_variable_unlinked(shader->ir) || progress; + progress = do_constant_folding(shader->ir) || progress; + progress = do_vec_index_to_swizzle(shader->ir) || progress; + progress = do_swizzle_swizzle(shader->ir) || progress; } while (progress); } - validate_ir_tree(&shader->ir); + validate_ir_tree(shader->ir); /* Print out the resulting IR */ if (!state->error && dump_lir) { - _mesa_print_ir(&shader->ir, state); + _mesa_print_ir(shader->ir, state); } shader->symbols = state->symbols; @@ -214,12 +212,12 @@ main(int argc, char **argv) assert(whole_program != NULL); for (/* empty */; argc > optind; optind++) { - whole_program->Shaders = (struct glsl_shader **) + whole_program->Shaders = (struct gl_shader **) talloc_realloc(whole_program, whole_program->Shaders, - struct glsl_shader *, whole_program->NumShaders + 1); + struct gl_shader *, whole_program->NumShaders + 1); assert(whole_program->Shaders != NULL); - struct glsl_shader *shader = talloc_zero(whole_program, glsl_shader); + struct gl_shader *shader = talloc_zero(whole_program, gl_shader); whole_program->Shaders[whole_program->NumShaders] = shader; whole_program->NumShaders++; @@ -238,8 +236,7 @@ main(int argc, char **argv) else usage_fail(argv[0]); - shader->Source = load_text_file(whole_program, - argv[optind], &shader->SourceLen); + shader->Source = load_text_file(whole_program, argv[optind]); if (shader->Source == NULL) { printf("File \"%s\" does not exist.\n", argv[optind]); exit(EXIT_FAILURE); diff --git a/src/glsl/program.h b/src/glsl/program.h index fd8197a45a..19c3a3e611 100644 --- a/src/glsl/program.h +++ b/src/glsl/program.h @@ -29,24 +29,6 @@ extern "C" { #include "shader/prog_uniform.h" } -/** - * Based on gl_shader in Mesa's mtypes.h. - */ -struct glsl_shader { - GLenum Type; - GLuint Name; - GLint RefCount; - GLboolean DeletePending; - GLboolean CompileStatus; - const GLchar *Source; /**< Source code string */ - size_t SourceLen; - GLchar *InfoLog; - - struct exec_list ir; - struct glsl_symbol_table *symbols; - struct gl_shader *mesa_shader; -}; - /** * Based on gl_shader_program in Mesa's mtypes.h. */ @@ -57,14 +39,14 @@ struct glsl_program { GLboolean DeletePending; GLuint NumShaders; /**< number of attached shaders */ - struct glsl_shader **Shaders; /**< List of attached the shaders */ + struct gl_shader **Shaders; /**< List of attached the shaders */ /** * Per-stage shaders resulting from the first stage of linking. */ /*@{*/ unsigned _NumLinkedShaders; - struct glsl_shader **_LinkedShaders; + struct gl_shader **_LinkedShaders; /*@}*/ /** User-defined attribute bindings (glBindAttribLocation) */ diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index c34d9bac4a..6fc7e29baf 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -1966,6 +1966,9 @@ struct gl_shader struct gl_program *Program; /**< Post-compile assembly code */ GLchar *InfoLog; struct gl_sl_pragmas Pragmas; + + struct exec_list *ir; + struct glsl_symbol_table *symbols; }; diff --git a/src/mesa/shader/ir_to_mesa.cpp b/src/mesa/shader/ir_to_mesa.cpp index 85ede3e328..c2dde312ef 100644 --- a/src/mesa/shader/ir_to_mesa.cpp +++ b/src/mesa/shader/ir_to_mesa.cpp @@ -1561,13 +1561,12 @@ link_uniforms_to_shared_uniform_list(struct gl_uniform_list *uniforms, } struct gl_program * -get_mesa_program(GLcontext *ctx, void *mem_ctx, struct glsl_shader *shader) +get_mesa_program(GLcontext *ctx, void *mem_ctx, struct gl_shader *shader) { ir_to_mesa_visitor v; struct prog_instruction *mesa_instructions, *mesa_inst; ir_instruction **mesa_instruction_annotation; int i; - exec_list *instructions = &shader->ir; struct gl_program *prog; GLenum target; @@ -1587,7 +1586,7 @@ get_mesa_program(GLcontext *ctx, void *mem_ctx, struct glsl_shader *shader) v.prog = prog; v.mem_ctx = talloc_new(NULL); - visit_exec_list(instructions, &v); + visit_exec_list(shader->ir, &v); v.ir_to_mesa_emit_op1(NULL, OPCODE_END, ir_to_mesa_undef_dst, ir_to_mesa_undef); @@ -1635,27 +1634,18 @@ get_mesa_program(GLcontext *ctx, void *mem_ctx, struct glsl_shader *shader) prog->Instructions = mesa_instructions; prog->NumInstructions = num_instructions; - _mesa_reference_program(ctx, &shader->mesa_shader->Program, prog); + _mesa_reference_program(ctx, &shader->Program, prog); return prog; } -/* Takes a Mesa gl shader structure and compiles it, returning our Mesa-like - * structure with the IR and such attached. - */ -static struct glsl_shader * -_mesa_get_glsl_shader(GLcontext *ctx, void *mem_ctx, struct gl_shader *sh) +extern "C" { + +void +_mesa_glsl_compile_shader(GLcontext *ctx, struct gl_shader *shader) { - struct glsl_shader *shader = talloc_zero(mem_ctx, struct glsl_shader); struct _mesa_glsl_parse_state *state; - shader->Type = sh->Type; - shader->Name = sh->Name; - shader->RefCount = 1; - shader->Source = sh->Source; - shader->SourceLen = strlen(sh->Source); - shader->mesa_shader = sh; - state = talloc_zero(shader, struct _mesa_glsl_parse_state); switch (shader->Type) { case GL_VERTEX_SHADER: state->target = vertex_shader; break; @@ -1665,7 +1655,7 @@ _mesa_get_glsl_shader(GLcontext *ctx, void *mem_ctx, struct gl_shader *sh) state->scanner = NULL; state->translation_unit.make_empty(); - state->symbols = new(mem_ctx) glsl_symbol_table; + state->symbols = new(shader) glsl_symbol_table; state->info_log = talloc_strdup(shader, ""); state->error = false; state->temp_index = 0; @@ -1686,25 +1676,25 @@ _mesa_get_glsl_shader(GLcontext *ctx, void *mem_ctx, struct gl_shader *sh) _mesa_glsl_lexer_dtor(state); } - shader->ir.make_empty(); + shader->ir = new(shader) exec_list; if (!state->error && !state->translation_unit.is_empty()) - _mesa_ast_to_hir(&shader->ir, state); + _mesa_ast_to_hir(shader->ir, state); /* Optimization passes */ - if (!state->error && !shader->ir.is_empty()) { + if (!state->error && !shader->ir->is_empty()) { bool progress; do { progress = false; - progress = do_function_inlining(&shader->ir) || progress; - progress = do_if_simplification(&shader->ir) || progress; - progress = do_copy_propagation(&shader->ir) || progress; - progress = do_dead_code_local(&shader->ir) || progress; - progress = do_dead_code_unlinked(state, &shader->ir) || progress; - progress = do_constant_variable_unlinked(&shader->ir) || progress; - progress = do_constant_folding(&shader->ir) || progress; - progress = do_vec_index_to_swizzle(&shader->ir) || progress; - progress = do_swizzle_swizzle(&shader->ir) || progress; + progress = do_function_inlining(shader->ir) || progress; + progress = do_if_simplification(shader->ir) || progress; + progress = do_copy_propagation(shader->ir) || progress; + progress = do_dead_code_local(shader->ir) || progress; + progress = do_dead_code_unlinked(state, shader->ir) || progress; + progress = do_constant_variable_unlinked(shader->ir) || progress; + progress = do_constant_folding(shader->ir) || progress; + progress = do_vec_index_to_swizzle(shader->ir) || progress; + progress = do_swizzle_swizzle(shader->ir) || progress; } while (progress); } @@ -1714,23 +1704,6 @@ _mesa_get_glsl_shader(GLcontext *ctx, void *mem_ctx, struct gl_shader *sh) shader->InfoLog = state->info_log; talloc_free(state); - - return shader; -} - -extern "C" { - -void -_mesa_glsl_compile_shader(GLcontext *ctx, struct gl_shader *sh) -{ - struct glsl_shader *shader; - TALLOC_CTX *mem_ctx = talloc_new(NULL); - - shader = _mesa_get_glsl_shader(ctx, mem_ctx, sh); - - sh->CompileStatus = shader->CompileStatus; - sh->InfoLog = strdup(shader->InfoLog); - talloc_free(mem_ctx); } void @@ -1738,18 +1711,16 @@ _mesa_glsl_link_shader(GLcontext *ctx, struct gl_shader_program *prog) { struct glsl_program *whole_program; unsigned int i; - _mesa_clear_shader_program_data(ctx, prog); whole_program = talloc_zero(NULL, struct glsl_program); whole_program->LinkStatus = GL_TRUE; whole_program->NumShaders = prog->NumShaders; - whole_program->Shaders = talloc_array(whole_program, struct glsl_shader *, + whole_program->Shaders = talloc_array(whole_program, struct gl_shader *, prog->NumShaders); for (i = 0; i < prog->NumShaders; i++) { - whole_program->Shaders[i] = _mesa_get_glsl_shader(ctx, whole_program, - prog->Shaders[i]); + whole_program->Shaders[i] = prog->Shaders[i]; if (!whole_program->Shaders[i]->CompileStatus) { whole_program->InfoLog = talloc_asprintf_append(whole_program->InfoLog, diff --git a/src/mesa/shader/shader_api.c b/src/mesa/shader/shader_api.c index a584f6072c..40b8286a13 100644 --- a/src/mesa/shader/shader_api.c +++ b/src/mesa/shader/shader_api.c @@ -44,7 +44,7 @@ #include "shader/prog_uniform.h" #include "shader/shader_api.h" #include "shader/uniforms.h" - +#include "talloc.h" /** * Allocate a new gl_shader_program object, initialize it. @@ -253,7 +253,7 @@ _mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type) { struct gl_shader *shader; assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER); - shader = CALLOC_STRUCT(gl_shader); + shader = talloc_zero(NULL, struct gl_shader); if (shader) { shader->Type = type; shader->Name = name; @@ -268,10 +268,8 @@ _mesa_free_shader(GLcontext *ctx, struct gl_shader *sh) { if (sh->Source) free((void *) sh->Source); - if (sh->InfoLog) - free(sh->InfoLog); _mesa_reference_program(ctx, &sh->Program, NULL); - free(sh); + talloc_free(sh); } -- cgit v1.2.3 From 849e18153cd91d812f694b806a84008498860bc3 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 30 Jun 2010 11:49:17 -0700 Subject: glsl2: Use Mesa's gl_shader_program instead of our own struct glsl_program. This avoids more allocation and shuffling of data around. --- src/glsl/linker.cpp | 16 ++++++++-------- src/glsl/main.cpp | 4 ++-- src/glsl/program.h | 34 +--------------------------------- src/mesa/main/mtypes.h | 3 +++ src/mesa/shader/ir_to_mesa.cpp | 39 +++++++++++++++++++-------------------- src/mesa/shader/shader_api.c | 6 +++--- 6 files changed, 36 insertions(+), 66 deletions(-) (limited to 'src/glsl/main.cpp') diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp index df71f21b54..719cae2f27 100644 --- a/src/glsl/linker.cpp +++ b/src/glsl/linker.cpp @@ -116,7 +116,7 @@ private: void -linker_error_printf(glsl_program *prog, const char *fmt, ...) +linker_error_printf(gl_shader_program *prog, const char *fmt, ...) { va_list ap; @@ -186,7 +186,7 @@ count_attribute_slots(const glsl_type *t) * \param shader Vertex shader executable to be verified */ bool -validate_vertex_shader_executable(struct glsl_program *prog, +validate_vertex_shader_executable(struct gl_shader_program *prog, struct gl_shader *shader) { if (shader == NULL) @@ -215,7 +215,7 @@ validate_vertex_shader_executable(struct glsl_program *prog, * \param shader Fragment shader executable to be verified */ bool -validate_fragment_shader_executable(struct glsl_program *prog, +validate_fragment_shader_executable(struct gl_shader_program *prog, struct gl_shader *shader) { if (shader == NULL) @@ -252,7 +252,7 @@ validate_fragment_shader_executable(struct glsl_program *prog, * Perform validation of uniforms used across multiple shader stages */ bool -cross_validate_uniforms(struct glsl_program *prog) +cross_validate_uniforms(struct gl_shader_program *prog) { /* Examine all of the uniforms in all of the shaders and cross validate * them. @@ -308,7 +308,7 @@ cross_validate_uniforms(struct glsl_program *prog) * Validate that outputs from one stage match inputs of another */ bool -cross_validate_outputs_to_inputs(struct glsl_program *prog, +cross_validate_outputs_to_inputs(struct gl_shader_program *prog, gl_shader *producer, gl_shader *consumer) { glsl_symbol_table parameters; @@ -412,7 +412,7 @@ struct uniform_node { }; void -assign_uniform_locations(struct glsl_program *prog) +assign_uniform_locations(struct gl_shader_program *prog) { /* */ exec_list uniforms; @@ -533,7 +533,7 @@ find_available_slots(unsigned used_mask, unsigned needed_count) bool -assign_attribute_locations(glsl_program *prog, unsigned max_attribute_index) +assign_attribute_locations(gl_shader_program *prog, unsigned max_attribute_index) { /* Mark invalid attribute locations as being used. */ @@ -767,7 +767,7 @@ assign_varying_locations(gl_shader *producer, gl_shader *consumer) void -link_shaders(struct glsl_program *prog) +link_shaders(struct gl_shader_program *prog) { prog->LinkStatus = false; prog->Validated = false; diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp index e78af42ac6..1ed22e1f33 100644 --- a/src/glsl/main.cpp +++ b/src/glsl/main.cpp @@ -206,9 +206,9 @@ main(int argc, char **argv) if (argc <= optind) usage_fail(argv[0]); - struct glsl_program *whole_program; + struct gl_shader_program *whole_program; - whole_program = talloc_zero (NULL, struct glsl_program); + whole_program = talloc_zero (NULL, struct gl_shader_program); assert(whole_program != NULL); for (/* empty */; argc > optind; optind++) { diff --git a/src/glsl/program.h b/src/glsl/program.h index 19c3a3e611..bb1cd919cd 100644 --- a/src/glsl/program.h +++ b/src/glsl/program.h @@ -29,37 +29,5 @@ extern "C" { #include "shader/prog_uniform.h" } -/** - * Based on gl_shader_program in Mesa's mtypes.h. - */ -struct glsl_program { - GLenum Type; /**< Always GL_SHADER_PROGRAM (internal token) */ - GLuint Name; /**< aka handle or ID */ - GLint RefCount; /**< Reference count */ - GLboolean DeletePending; - - GLuint NumShaders; /**< number of attached shaders */ - struct gl_shader **Shaders; /**< List of attached the shaders */ - - /** - * Per-stage shaders resulting from the first stage of linking. - */ - /*@{*/ - unsigned _NumLinkedShaders; - struct gl_shader **_LinkedShaders; - /*@}*/ - - /** User-defined attribute bindings (glBindAttribLocation) */ - struct gl_program_parameter_list *Attributes; - - /* post-link info: */ - struct gl_uniform_list *Uniforms; - struct gl_program_parameter_list *Varying; - GLboolean LinkStatus; /**< GL_LINK_STATUS */ - GLboolean Validated; - GLboolean _Used; /**< Ever used for drawing? */ - GLchar *InfoLog; -}; - extern void -link_shaders(struct glsl_program *prog); +link_shaders(struct gl_shader_program *prog); diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index 6fc7e29baf..bc90b1e044 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -2005,6 +2005,9 @@ struct gl_shader_program GLboolean Validated; GLboolean _Used; /**< Ever used for drawing? */ GLchar *InfoLog; + + GLuint _NumLinkedShaders; + struct gl_shader **_LinkedShaders; }; diff --git a/src/mesa/shader/ir_to_mesa.cpp b/src/mesa/shader/ir_to_mesa.cpp index c2dde312ef..f0eb46a3ee 100644 --- a/src/mesa/shader/ir_to_mesa.cpp +++ b/src/mesa/shader/ir_to_mesa.cpp @@ -1709,48 +1709,49 @@ _mesa_glsl_compile_shader(GLcontext *ctx, struct gl_shader *shader) void _mesa_glsl_link_shader(GLcontext *ctx, struct gl_shader_program *prog) { - struct glsl_program *whole_program; unsigned int i; + _mesa_clear_shader_program_data(ctx, prog); - whole_program = talloc_zero(NULL, struct glsl_program); - whole_program->LinkStatus = GL_TRUE; - whole_program->NumShaders = prog->NumShaders; - whole_program->Shaders = talloc_array(whole_program, struct gl_shader *, - prog->NumShaders); + prog->LinkStatus = GL_TRUE; for (i = 0; i < prog->NumShaders; i++) { - whole_program->Shaders[i] = prog->Shaders[i]; - if (!whole_program->Shaders[i]->CompileStatus) { - whole_program->InfoLog = - talloc_asprintf_append(whole_program->InfoLog, + if (!prog->Shaders[i]->CompileStatus) { + prog->InfoLog = + talloc_asprintf_append(prog->InfoLog, "linking with uncompiled shader"); - whole_program->LinkStatus = GL_FALSE; + prog->LinkStatus = GL_FALSE; } } - prog->Uniforms = _mesa_new_uniform_list(); prog->Varying = _mesa_new_parameter_list(); _mesa_reference_vertprog(ctx, &prog->VertexProgram, NULL); _mesa_reference_fragprog(ctx, &prog->FragmentProgram, NULL); - if (whole_program->LinkStatus) - link_shaders(whole_program); + if (prog->LinkStatus) { + link_shaders(prog); + + /* We don't use the linker's uniforms list, and cook up our own at + * generate time. + */ + free(prog->Uniforms); + prog->Uniforms = _mesa_new_uniform_list(); + } - prog->LinkStatus = whole_program->LinkStatus; + prog->LinkStatus = prog->LinkStatus; /* FINISHME: This should use the linker-generated code */ if (prog->LinkStatus) { for (i = 0; i < prog->NumShaders; i++) { struct gl_program *linked_prog; - linked_prog = get_mesa_program(ctx, whole_program, - whole_program->Shaders[i]); + linked_prog = get_mesa_program(ctx, prog, + prog->Shaders[i]); count_resources(linked_prog); link_uniforms_to_shared_uniform_list(prog->Uniforms, linked_prog); - switch (whole_program->Shaders[i]->Type) { + switch (prog->Shaders[i]->Type) { case GL_VERTEX_SHADER: _mesa_reference_vertprog(ctx, &prog->VertexProgram, (struct gl_vertex_program *)linked_prog); @@ -1766,8 +1767,6 @@ _mesa_glsl_link_shader(GLcontext *ctx, struct gl_shader_program *prog) } } } - - talloc_free(whole_program); } } /* extern "C" */ diff --git a/src/mesa/shader/shader_api.c b/src/mesa/shader/shader_api.c index 40b8286a13..f05ebc9fcb 100644 --- a/src/mesa/shader/shader_api.c +++ b/src/mesa/shader/shader_api.c @@ -53,7 +53,7 @@ static struct gl_shader_program * _mesa_new_shader_program(GLcontext *ctx, GLuint name) { struct gl_shader_program *shProg; - shProg = CALLOC_STRUCT(gl_shader_program); + shProg = talloc_zero(NULL, struct gl_shader_program); if (shProg) { shProg->Type = GL_SHADER_PROGRAM_MESA; shProg->Name = name; @@ -117,7 +117,7 @@ _mesa_free_shader_program_data(GLcontext *ctx, } if (shProg->InfoLog) { - free(shProg->InfoLog); + talloc_free(shProg->InfoLog); shProg->InfoLog = NULL; } @@ -139,7 +139,7 @@ _mesa_free_shader_program(GLcontext *ctx, struct gl_shader_program *shProg) { _mesa_free_shader_program_data(ctx, shProg); - free(shProg); + talloc_free(shProg); } -- cgit v1.2.3 From 116f1d4f95d8eb0a82b272016590549632c865b3 Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Fri, 25 Jun 2010 14:10:01 -0700 Subject: glsl2: Steal the live IR and free the rest of the junk. --- src/glsl/main.cpp | 11 +++++++++++ src/mesa/shader/ir_to_mesa.cpp | 11 +++++++++++ 2 files changed, 22 insertions(+) (limited to 'src/glsl/main.cpp') diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp index 1ed22e1f33..8b2eeaa13a 100644 --- a/src/glsl/main.cpp +++ b/src/glsl/main.cpp @@ -99,6 +99,12 @@ const struct option compiler_opts[] = { { NULL, 0, NULL, 0 } }; +static void +steal_memory(ir_instruction *ir, void *new_ctx) +{ + talloc_steal(new_ctx, ir); +} + void compile_shader(struct gl_shader *shader) { @@ -187,6 +193,11 @@ compile_shader(struct gl_shader *shader) shader->InfoLog = state->info_log; + /* Retain any live IR, but trash the rest. */ + foreach_list(node, shader->ir) { + visit_tree((ir_instruction *) node, steal_memory, shader); + } + talloc_free(state); return; diff --git a/src/mesa/shader/ir_to_mesa.cpp b/src/mesa/shader/ir_to_mesa.cpp index 75021a70fd..c3de3aae05 100644 --- a/src/mesa/shader/ir_to_mesa.cpp +++ b/src/mesa/shader/ir_to_mesa.cpp @@ -1650,6 +1650,12 @@ get_mesa_program(GLcontext *ctx, void *mem_ctx, struct gl_shader *shader) extern "C" { +static void +steal_memory(ir_instruction *ir, void *new_ctx) +{ + talloc_steal(new_ctx, ir); +} + void _mesa_glsl_compile_shader(GLcontext *ctx, struct gl_shader *shader) { @@ -1712,6 +1718,11 @@ _mesa_glsl_compile_shader(GLcontext *ctx, struct gl_shader *shader) shader->CompileStatus = !state->error; shader->InfoLog = state->info_log; + /* Retain any live IR, but trash the rest. */ + foreach_list(node, shader->ir) { + visit_tree((ir_instruction *) node, steal_memory, shader); + } + talloc_free(state); } -- cgit v1.2.3 From 629198b96a8f471c48932d6af56184b6c33b5fe5 Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Tue, 29 Jun 2010 11:31:04 -0700 Subject: glsl2: Preprocessed source doesn't need to live past compile time. --- src/glsl/main.cpp | 5 +---- src/mesa/shader/ir_to_mesa.cpp | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) (limited to 'src/glsl/main.cpp') diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp index 8b2eeaa13a..fa63853b47 100644 --- a/src/glsl/main.cpp +++ b/src/glsl/main.cpp @@ -129,11 +129,8 @@ compile_shader(struct gl_shader *shader) state->Const.MaxDrawBuffers = 2; - /* Create a new context for the preprocessor output. Ultimately, this - * should probably be the parser context, but there isn't one yet. - */ const char *source = shader->Source; - state->error = preprocess(shader, &source, &state->info_log); + state->error = preprocess(state, &source, &state->info_log); if (!state->error) { _mesa_glsl_lexer_ctor(state, source); diff --git a/src/mesa/shader/ir_to_mesa.cpp b/src/mesa/shader/ir_to_mesa.cpp index c3de3aae05..4eac810679 100644 --- a/src/mesa/shader/ir_to_mesa.cpp +++ b/src/mesa/shader/ir_to_mesa.cpp @@ -1679,11 +1679,8 @@ _mesa_glsl_compile_shader(GLcontext *ctx, struct gl_shader *shader) state->Const.MaxDrawBuffers = ctx->Const.MaxDrawBuffers; - /* Create a new context for the preprocessor output. Ultimately, this - * should probably be the parser context, but there isn't one yet. - */ const char *source = shader->Source; - state->error = preprocess(shader, &source, &state->info_log); + state->error = preprocess(state, &source, &state->info_log); if (!state->error) { _mesa_glsl_lexer_ctor(state, source); -- cgit v1.2.3 From 127308b4be077e5bdf60f76320307550921e86bb Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Thu, 1 Jul 2010 13:30:50 -0700 Subject: glsl2: Add gl_MaxTextureCoords --- src/glsl/ast_to_hir.cpp | 12 ++++-------- src/glsl/glsl_parser_extras.h | 1 + src/glsl/ir_variable.cpp | 31 +++++++++++++++++-------------- src/glsl/main.cpp | 1 + src/mesa/shader/ir_to_mesa.cpp | 1 + 5 files changed, 24 insertions(+), 22 deletions(-) (limited to 'src/glsl/main.cpp') diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp index 22d9f7ad53..fc5a652f25 100644 --- a/src/glsl/ast_to_hir.cpp +++ b/src/glsl/ast_to_hir.cpp @@ -1817,20 +1817,16 @@ ast_declarator_list::hir(exec_list *instructions, * * "The size [of gl_TexCoord] can be at most * gl_MaxTextureCoords." - * - * FINISHME: Every platform that supports GLSL sets - * FINISHME: gl_MaxTextureCoords to at least 4, so hard-code 4 - * FINISHME: for now. */ + const unsigned size = unsigned(var->type->array_size()); if ((strcmp("gl_TexCoord", var->name) == 0) - && (var->type->array_size() > 4)) { + && (size > state->Const.MaxTextureCoords)) { YYLTYPE loc = this->get_location(); _mesa_glsl_error(& loc, state, "`gl_TexCoord' array size cannot " "be larger than gl_MaxTextureCoords (%u)\n", - 4); - } else if (var->type->array_size() <= - (int)earlier->max_array_access) { + state->Const.MaxTextureCoords); + } else if (size <= earlier->max_array_access) { YYLTYPE loc = this->get_location(); _mesa_glsl_error(& loc, state, "array size must be > %u due to " diff --git a/src/glsl/glsl_parser_extras.h b/src/glsl/glsl_parser_extras.h index f957a926be..3aeba83cc5 100644 --- a/src/glsl/glsl_parser_extras.h +++ b/src/glsl/glsl_parser_extras.h @@ -50,6 +50,7 @@ struct _mesa_glsl_parse_state { */ struct { unsigned MaxDrawBuffers; + unsigned MaxTextureCoords; } Const; /** diff --git a/src/glsl/ir_variable.cpp b/src/glsl/ir_variable.cpp index d43809ef9c..9daad803e9 100644 --- a/src/glsl/ir_variable.cpp +++ b/src/glsl/ir_variable.cpp @@ -96,25 +96,28 @@ add_builtin_variable(const builtin_variable *proto, exec_list *instructions, static void generate_110_uniforms(exec_list *instructions, - glsl_symbol_table *symtab) + struct _mesa_glsl_parse_state *state) { for (unsigned i = 0 ; i < Elements(builtin_110_deprecated_uniforms) ; i++) { add_builtin_variable(& builtin_110_deprecated_uniforms[i], - instructions, symtab); + instructions, state->symbols); } - /* FINISHME: The size of this array is implementation dependent based on the - * FINISHME: value of GL_MAX_TEXTURE_COORDS. Every platform that supports - * FINISHME: GLSL sets GL_MAX_TEXTURE_COORDS to at least 4, so hard-code 4 - * FINISHME: for now. - */ + ir_variable *const mtc = add_variable("gl_MaxTextureCoords", ir_var_auto, + -1, glsl_type::int_type, + instructions, state->symbols); + mtc->constant_value = new(mtc) + ir_constant(int(state->Const.MaxTextureCoords)); + + const glsl_type *const mat4_array_type = - glsl_type::get_array_instance(symtab, glsl_type::mat4_type, 4); + glsl_type::get_array_instance(state->symbols, glsl_type::mat4_type, + state->Const.MaxTextureCoords); add_variable("gl_TextureMatrix", ir_var_uniform, -1, mat4_array_type, - instructions, symtab); + instructions, state->symbols); /* FINISHME: Add support for gl_DepthRangeParameters */ /* FINISHME: Add support for gl_ClipPlane[] */ @@ -129,11 +132,11 @@ generate_110_uniforms(exec_list *instructions, * FINISHME: at least 8, so hard-code 8 for now. */ const glsl_type *const light_source_array_type = - glsl_type::get_array_instance(symtab, - symtab->get_type("gl_LightSourceParameters"), 8); + glsl_type::get_array_instance(state->symbols, + state->symbols->get_type("gl_LightSourceParameters"), 8); add_variable("gl_LightSource", ir_var_uniform, -1, light_source_array_type, - instructions, symtab); + instructions, state->symbols); /* FINISHME: Add support for gl_LightModel */ /* FINISHME: Add support for gl_FrontLightProduct[], gl_BackLightProduct[] */ @@ -157,7 +160,7 @@ generate_110_vs_variables(exec_list *instructions, add_builtin_variable(& builtin_110_deprecated_vs_variables[i], instructions, state->symbols); } - generate_110_uniforms(instructions, state->symbols); + generate_110_uniforms(instructions, state); /* From page 54 (page 60 of the PDF) of the GLSL 1.20 spec: * @@ -247,7 +250,7 @@ generate_110_fs_variables(exec_list *instructions, add_builtin_variable(& builtin_110_deprecated_fs_variables[i], instructions, state->symbols); } - generate_110_uniforms(instructions, state->symbols); + generate_110_uniforms(instructions, state); /* From page 54 (page 60 of the PDF) of the GLSL 1.20 spec: * diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp index fa63853b47..c833c9cde6 100644 --- a/src/glsl/main.cpp +++ b/src/glsl/main.cpp @@ -128,6 +128,7 @@ compile_shader(struct gl_shader *shader) state->ARB_texture_rectangle_enable = true; state->Const.MaxDrawBuffers = 2; + state->Const.MaxTextureCoords = 4; const char *source = shader->Source; state->error = preprocess(state, &source, &state->info_log); diff --git a/src/mesa/shader/ir_to_mesa.cpp b/src/mesa/shader/ir_to_mesa.cpp index 1e186354c5..14abf602af 100644 --- a/src/mesa/shader/ir_to_mesa.cpp +++ b/src/mesa/shader/ir_to_mesa.cpp @@ -1710,6 +1710,7 @@ _mesa_glsl_compile_shader(GLcontext *ctx, struct gl_shader *shader) state->ARB_texture_rectangle_enable = true; state->Const.MaxDrawBuffers = ctx->Const.MaxDrawBuffers; + state->Const.MaxTextureCoords = ctx->Const.MaxTextureCoordUnits; const char *source = shader->Source; state->error = preprocess(state, &source, &state->info_log); -- cgit v1.2.3 From 06143ea09411aa283ac3633bfbfa4326584cd952 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Wed, 30 Jun 2010 16:27:22 -0700 Subject: glsl2: Conditionally define preprocessor tokens for optional extensions The only optional extension currently supported by the compiler is GL_EXT_texture_array. --- src/glsl/glcpp/glcpp-parse.y | 10 +++++++++- src/glsl/glcpp/glcpp.c | 5 +---- src/glsl/glcpp/glcpp.h | 7 +++++-- src/glsl/glcpp/pp.c | 5 +++-- src/glsl/glsl_parser_extras.h | 3 ++- src/glsl/main.cpp | 4 +++- src/mesa/shader/ir_to_mesa.cpp | 3 ++- 7 files changed, 25 insertions(+), 12 deletions(-) (limited to 'src/glsl/main.cpp') diff --git a/src/glsl/glcpp/glcpp-parse.y b/src/glsl/glcpp/glcpp-parse.y index d4cb006bbc..e5544fe29b 100644 --- a/src/glsl/glcpp/glcpp-parse.y +++ b/src/glsl/glcpp/glcpp-parse.y @@ -28,6 +28,7 @@ #include #include "glcpp.h" +#include "main/mtypes.h" #define glcpp_print(stream, str) stream = talloc_strdup_append(stream, str) #define glcpp_printf(stream, fmt, args...) \ @@ -894,7 +895,7 @@ yyerror (YYLTYPE *locp, glcpp_parser_t *parser, const char *error) } glcpp_parser_t * -glcpp_parser_create (void) +glcpp_parser_create (const struct gl_extensions *extensions) { glcpp_parser_t *parser; token_t *tok; @@ -932,6 +933,13 @@ glcpp_parser_create (void) _token_list_append(list, tok); _define_object_macro(parser, NULL, "GL_ARB_texture_rectangle", list); + if ((extensions != NULL) && extensions->EXT_texture_array) { + list = _token_list_create(parser); + _token_list_append(list, tok); + _define_object_macro(parser, NULL, + "GL_EXT_texture_array", list); + } + talloc_unlink(parser, tok); return parser; diff --git a/src/glsl/glcpp/glcpp.c b/src/glsl/glcpp/glcpp.c index cc87e14950..a245cb5406 100644 --- a/src/glsl/glcpp/glcpp.c +++ b/src/glsl/glcpp/glcpp.c @@ -68,16 +68,13 @@ load_text_file(void *ctx, const char *file_name) return text; } -int -preprocess(void *talloc_ctx, const char **shader, char **info_log); - int main (void) { void *ctx = talloc(NULL, void*); const char *shader = load_text_file(ctx, NULL); char *info_log = talloc_strdup(ctx, ""); - int ret = preprocess(ctx, &shader, &info_log); + int ret = preprocess(ctx, &shader, &info_log, NULL); printf("%s", shader); fprintf(stderr, "%s", info_log); diff --git a/src/glsl/glcpp/glcpp.h b/src/glsl/glcpp/glcpp.h index 2cfa98d2b1..fc9511a67a 100644 --- a/src/glsl/glcpp/glcpp.h +++ b/src/glsl/glcpp/glcpp.h @@ -158,8 +158,10 @@ struct glcpp_parser { int error; }; +struct gl_extensions; + glcpp_parser_t * -glcpp_parser_create (void); +glcpp_parser_create (const struct gl_extensions *extensions); int glcpp_parser_parse (glcpp_parser_t *parser); @@ -168,7 +170,8 @@ void glcpp_parser_destroy (glcpp_parser_t *parser); int -preprocess(void *talloc_ctx, const char **shader, char **info_log); +preprocess(void *talloc_ctx, const char **shader, char **info_log, + const struct gl_extensions *extensions); /* Functions for writing to the info log */ diff --git a/src/glsl/glcpp/pp.c b/src/glsl/glcpp/pp.c index a25b7b72a6..1ce829a2c9 100644 --- a/src/glsl/glcpp/pp.c +++ b/src/glsl/glcpp/pp.c @@ -134,10 +134,11 @@ remove_line_continuations(glcpp_parser_t *ctx, const char *shader) } extern int -preprocess(void *talloc_ctx, const char **shader, char **info_log) +preprocess(void *talloc_ctx, const char **shader, char **info_log, + const struct gl_extensions *extensions) { int errors; - glcpp_parser_t *parser = glcpp_parser_create (); + glcpp_parser_t *parser = glcpp_parser_create (extensions); *shader = remove_line_continuations(parser, *shader); glcpp_lex_set_source_string (parser, *shader); diff --git a/src/glsl/glsl_parser_extras.h b/src/glsl/glsl_parser_extras.h index 3aeba83cc5..dc3d23ac54 100644 --- a/src/glsl/glsl_parser_extras.h +++ b/src/glsl/glsl_parser_extras.h @@ -115,7 +115,8 @@ extern void _mesa_glsl_warning(const YYLTYPE *locp, const char *fmt, ...); extern "C" { -extern int preprocess(void *ctx, const char **shader, char **info_log); +extern int preprocess(void *ctx, const char **shader, char **info_log, + const struct gl_extensions *extensions); } extern void _mesa_glsl_lexer_ctor(struct _mesa_glsl_parse_state *state, diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp index c833c9cde6..deaab7e033 100644 --- a/src/glsl/main.cpp +++ b/src/glsl/main.cpp @@ -109,6 +109,7 @@ void compile_shader(struct gl_shader *shader) { struct _mesa_glsl_parse_state *state; + struct gl_extensions ext; state = talloc_zero(talloc_parent(shader), struct _mesa_glsl_parse_state); @@ -127,11 +128,12 @@ compile_shader(struct gl_shader *shader) state->loop_or_switch_nesting = NULL; state->ARB_texture_rectangle_enable = true; + memset(&ext, 0, sizeof(ext)); state->Const.MaxDrawBuffers = 2; state->Const.MaxTextureCoords = 4; const char *source = shader->Source; - state->error = preprocess(state, &source, &state->info_log); + state->error = preprocess(state, &source, &state->info_log, &ext); if (!state->error) { _mesa_glsl_lexer_ctor(state, source); diff --git a/src/mesa/shader/ir_to_mesa.cpp b/src/mesa/shader/ir_to_mesa.cpp index 14abf602af..918004c79f 100644 --- a/src/mesa/shader/ir_to_mesa.cpp +++ b/src/mesa/shader/ir_to_mesa.cpp @@ -1713,7 +1713,8 @@ _mesa_glsl_compile_shader(GLcontext *ctx, struct gl_shader *shader) state->Const.MaxTextureCoords = ctx->Const.MaxTextureCoordUnits; const char *source = shader->Source; - state->error = preprocess(state, &source, &state->info_log); + state->error = preprocess(state, &source, &state->info_log, + &ctx->Extensions); if (!state->error) { _mesa_glsl_lexer_ctor(state, source); -- cgit v1.2.3 From 667f4e1940c4c4660e35dc9906672a476369660f Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Wed, 30 Jun 2010 16:42:07 -0700 Subject: glsl2: Conditionally allow optional extensions to be enabled The only optional extension currently supported by the compiler is GL_EXT_texture_array. --- src/glsl/glsl_parser_extras.cpp | 6 ++++++ src/glsl/glsl_parser_extras.h | 3 +++ src/glsl/main.cpp | 1 + src/mesa/shader/ir_to_mesa.cpp | 1 + 4 files changed, 11 insertions(+) (limited to 'src/glsl/main.cpp') diff --git a/src/glsl/glsl_parser_extras.cpp b/src/glsl/glsl_parser_extras.cpp index 2e17c4c337..fc3f9e90b6 100644 --- a/src/glsl/glsl_parser_extras.cpp +++ b/src/glsl/glsl_parser_extras.cpp @@ -27,6 +27,7 @@ extern "C" { #include +#include "main/mtypes.h" } #include "ast.h" @@ -135,6 +136,11 @@ _mesa_glsl_process_extension(const char *name, YYLTYPE *name_locp, } 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 { unsupported = true; } diff --git a/src/glsl/glsl_parser_extras.h b/src/glsl/glsl_parser_extras.h index dc3d23ac54..16f7268181 100644 --- a/src/glsl/glsl_parser_extras.h +++ b/src/glsl/glsl_parser_extras.h @@ -90,6 +90,9 @@ struct _mesa_glsl_parse_state { unsigned EXT_texture_array_enable:1; unsigned EXT_texture_array_warn:1; /*@}*/ + + /** Extensions supported by the OpenGL implementation. */ + const struct gl_extensions *extensions; }; typedef struct YYLTYPE { diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp index deaab7e033..16bbc8cd3f 100644 --- a/src/glsl/main.cpp +++ b/src/glsl/main.cpp @@ -129,6 +129,7 @@ compile_shader(struct gl_shader *shader) state->ARB_texture_rectangle_enable = true; memset(&ext, 0, sizeof(ext)); + state->extensions = &ext; state->Const.MaxDrawBuffers = 2; state->Const.MaxTextureCoords = 4; diff --git a/src/mesa/shader/ir_to_mesa.cpp b/src/mesa/shader/ir_to_mesa.cpp index 918004c79f..7c7e368d0d 100644 --- a/src/mesa/shader/ir_to_mesa.cpp +++ b/src/mesa/shader/ir_to_mesa.cpp @@ -1709,6 +1709,7 @@ _mesa_glsl_compile_shader(GLcontext *ctx, struct gl_shader *shader) state->loop_or_switch_nesting = NULL; state->ARB_texture_rectangle_enable = true; + state->extensions = &ctx->Extensions; state->Const.MaxDrawBuffers = ctx->Const.MaxDrawBuffers; state->Const.MaxTextureCoords = ctx->Const.MaxTextureCoordUnits; -- cgit v1.2.3 From 4d962e66e319191d5b94291b6f55d720df71130a Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Fri, 2 Jul 2010 14:43:01 -0700 Subject: glsl2: Print the linking info log in the stand-alone compiler --- src/glsl/main.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/glsl/main.cpp') diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp index 16bbc8cd3f..9bed2c6bcc 100644 --- a/src/glsl/main.cpp +++ b/src/glsl/main.cpp @@ -266,6 +266,9 @@ main(int argc, char **argv) if ((status == EXIT_SUCCESS) && do_link) { link_shaders(whole_program); status = (whole_program->LinkStatus) ? EXIT_SUCCESS : EXIT_FAILURE; + + if (strlen(whole_program->InfoLog) > 0) + printf("Info log for linking:\n%s\n", whole_program->InfoLog); } talloc_free(whole_program); -- cgit v1.2.3 From a36334be02cb0a2b834667116bfeb680bf365857 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 6 Jul 2010 17:53:32 -0700 Subject: glsl2: Add pass for supporting variable vector indexing in rvalues. The Mesa IR needs this to support vector indexing correctly, and hardware backends such as 915 would want this behavior as well. Fixes glsl-vs-vec4-indexing-2. --- src/glsl/Makefile | 1 + src/glsl/ir_optimization.h | 1 + src/glsl/ir_vec_index_to_cond_assign.cpp | 197 +++++++++++++++++++++++++++++++ src/glsl/main.cpp | 1 + src/mesa/shader/ir_to_mesa.cpp | 6 + 5 files changed, 206 insertions(+) create mode 100644 src/glsl/ir_vec_index_to_cond_assign.cpp (limited to 'src/glsl/main.cpp') diff --git a/src/glsl/Makefile b/src/glsl/Makefile index 30ba475d92..d2a687aa33 100644 --- a/src/glsl/Makefile +++ b/src/glsl/Makefile @@ -47,6 +47,7 @@ CXX_SOURCES = \ ir_swizzle_swizzle.cpp \ ir_validate.cpp \ ir_variable.cpp \ + ir_vec_index_to_cond_assign.cpp \ ir_vec_index_to_swizzle.cpp \ linker.cpp \ s_expression.cpp diff --git a/src/glsl/ir_optimization.h b/src/glsl/ir_optimization.h index 6d02e591c3..93010dadbe 100644 --- a/src/glsl/ir_optimization.h +++ b/src/glsl/ir_optimization.h @@ -42,4 +42,5 @@ bool do_function_inlining(exec_list *instructions); bool do_if_simplification(exec_list *instructions); bool do_mod_to_fract(exec_list *instructions); bool do_swizzle_swizzle(exec_list *instructions); +bool do_vec_index_to_cond_assign(exec_list *instructions); bool do_vec_index_to_swizzle(exec_list *instructions); diff --git a/src/glsl/ir_vec_index_to_cond_assign.cpp b/src/glsl/ir_vec_index_to_cond_assign.cpp new file mode 100644 index 0000000000..6264a430e3 --- /dev/null +++ b/src/glsl/ir_vec_index_to_cond_assign.cpp @@ -0,0 +1,197 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_vec_index_to_cond_assign.cpp + * + * Turns indexing into vector types to a series of conditional moves + * of each channel's swizzle into a temporary. + * + * Most GPUs don't have a native way to do this operation, and this + * works around that. For drivers using both this pass and + * ir_vec_index_to_swizzle, there's a risk that this pass will happen + * before sufficient constant folding to find that the array index is + * constant. However, we hope that other optimization passes, + * particularly constant folding of assignment conditions and copy + * propagation, will result in the same code in the end. + */ + +#include "ir.h" +#include "ir_visitor.h" +#include "ir_optimization.h" +#include "glsl_types.h" + +/** + * Visitor class for replacing expressions with ir_constant values. + */ + +class ir_vec_index_to_cond_assign_visitor : public ir_hierarchical_visitor { +public: + ir_vec_index_to_cond_assign_visitor() + { + progress = false; + } + + ir_rvalue *convert_vec_index_to_cond_assign(ir_rvalue *val); + + virtual ir_visitor_status visit_enter(ir_expression *); + virtual ir_visitor_status visit_enter(ir_swizzle *); + virtual ir_visitor_status visit_enter(ir_assignment *); + virtual ir_visitor_status visit_enter(ir_return *); + virtual ir_visitor_status visit_enter(ir_call *); + virtual ir_visitor_status visit_enter(ir_if *); + + bool progress; +}; + +ir_rvalue * +ir_vec_index_to_cond_assign_visitor::convert_vec_index_to_cond_assign(ir_rvalue *ir) +{ + ir_dereference_array *orig_deref = ir->as_dereference_array(); + ir_assignment *assign; + ir_variable *index, *var; + ir_dereference *deref; + ir_expression *condition; + ir_swizzle *swizzle; + int i; + + if (!orig_deref) + return ir; + + if (orig_deref->array->type->is_matrix() || + orig_deref->array->type->is_array()) + return ir; + + assert(orig_deref->array_index->type->base_type == GLSL_TYPE_INT); + + /* Store the index to a temporary to avoid reusing its tree. */ + index = new(base_ir) ir_variable(glsl_type::int_type, + "vec_index_tmp_i"); + base_ir->insert_before(index); + deref = new(base_ir) ir_dereference_variable(index); + assign = new(base_ir) ir_assignment(deref, orig_deref->array_index, NULL); + base_ir->insert_before(assign); + + /* Temporary where we store whichever value we swizzle out. */ + var = new(base_ir) ir_variable(ir->type, "vec_index_tmp_v"); + base_ir->insert_before(var); + + /* Generate a conditional move of each vector element to the temp. */ + for (i = 0; i < orig_deref->array->type->vector_elements; i++) { + deref = new(base_ir) ir_dereference_variable(index); + condition = new(base_ir) ir_expression(ir_binop_equal, + glsl_type::bool_type, + deref, + new(base_ir) ir_constant(i)); + + /* Just clone the rest of the deref chain when trying to get at the + * underlying variable. + */ + deref = (ir_dereference *)orig_deref->array->clone(NULL); + swizzle = new(base_ir) ir_swizzle(deref, i, 0, 0, 0, 1); + + deref = new(base_ir) ir_dereference_variable(var); + assign = new(base_ir) ir_assignment(deref, swizzle, condition); + base_ir->insert_before(assign); + } + + this->progress = true; + return new(base_ir) ir_dereference_variable(var); +} + +ir_visitor_status +ir_vec_index_to_cond_assign_visitor::visit_enter(ir_expression *ir) +{ + unsigned int i; + + for (i = 0; i < ir->get_num_operands(); i++) { + ir->operands[i] = convert_vec_index_to_cond_assign(ir->operands[i]); + } + + return visit_continue; +} + +ir_visitor_status +ir_vec_index_to_cond_assign_visitor::visit_enter(ir_swizzle *ir) +{ + /* Can't be hit from normal GLSL, since you can't swizzle a scalar (which + * the result of indexing a vector is. But maybe at some point we'll end up + * using swizzling of scalars for vector construction. + */ + ir->val = convert_vec_index_to_cond_assign(ir->val); + + return visit_continue; +} + +ir_visitor_status +ir_vec_index_to_cond_assign_visitor::visit_enter(ir_assignment *ir) +{ + /* FINISHME: Handle it on the LHS. */ + ir->rhs = convert_vec_index_to_cond_assign(ir->rhs); + + return visit_continue; +} + +ir_visitor_status +ir_vec_index_to_cond_assign_visitor::visit_enter(ir_call *ir) +{ + foreach_iter(exec_list_iterator, iter, *ir) { + ir_rvalue *param = (ir_rvalue *)iter.get(); + ir_rvalue *new_param = convert_vec_index_to_cond_assign(param); + + if (new_param != param) { + param->insert_before(new_param); + param->remove(); + } + } + + return visit_continue; +} + +ir_visitor_status +ir_vec_index_to_cond_assign_visitor::visit_enter(ir_return *ir) +{ + if (ir->value) { + ir->value = convert_vec_index_to_cond_assign(ir->value); + } + + return visit_continue; +} + +ir_visitor_status +ir_vec_index_to_cond_assign_visitor::visit_enter(ir_if *ir) +{ + ir->condition = convert_vec_index_to_cond_assign(ir->condition); + + return visit_continue; +} + +bool +do_vec_index_to_cond_assign(exec_list *instructions) +{ + ir_vec_index_to_cond_assign_visitor v; + + visit_list_elements(&v, instructions); + + return v.progress; +} diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp index 9bed2c6bcc..782934a8d7 100644 --- a/src/glsl/main.cpp +++ b/src/glsl/main.cpp @@ -175,6 +175,7 @@ compile_shader(struct gl_shader *shader) progress = do_constant_variable_unlinked(shader->ir) || progress; progress = do_constant_folding(shader->ir) || progress; progress = do_vec_index_to_swizzle(shader->ir) || progress; + progress = do_vec_index_to_cond_assign(shader->ir) || progress; progress = do_swizzle_swizzle(shader->ir) || progress; } while (progress); } diff --git a/src/mesa/shader/ir_to_mesa.cpp b/src/mesa/shader/ir_to_mesa.cpp index 021e270f18..daf09e9e65 100644 --- a/src/mesa/shader/ir_to_mesa.cpp +++ b/src/mesa/shader/ir_to_mesa.cpp @@ -1821,7 +1821,13 @@ _mesa_glsl_compile_shader(GLcontext *ctx, struct gl_shader *shader) progress = do_dead_code_unlinked(state, shader->ir) || progress; progress = do_constant_variable_unlinked(shader->ir) || progress; progress = do_constant_folding(shader->ir) || progress; + progress = do_vec_index_to_swizzle(shader->ir) || progress; + /* Do this one after the previous to let the easier pass handle + * constant vector indexing. + */ + progress = do_vec_index_to_cond_assign(shader->ir) || progress; + progress = do_swizzle_swizzle(shader->ir) || progress; } while (progress); } -- cgit v1.2.3 From dfd30ca6a95a7d95835dad78ffe1fba4d1f4ef69 Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Thu, 8 Jul 2010 12:40:52 -0700 Subject: glsl2: Remove generate_temporary and global temporary counter. Most places in the code simply use a static name, which works because names are never used to look up an ir_variable. generate_temporary is simply unnecessary (and looks like it would leak memory, and isn't thread safe...) --- src/glsl/ast_to_hir.cpp | 32 +++++--------------------------- src/glsl/glsl_parser_extras.h | 3 --- src/glsl/main.cpp | 1 - src/mesa/shader/ir_to_mesa.cpp | 1 - 4 files changed, 5 insertions(+), 32 deletions(-) (limited to 'src/glsl/main.cpp') diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp index e716b8a11e..e03bb6394f 100644 --- a/src/glsl/ast_to_hir.cpp +++ b/src/glsl/ast_to_hir.cpp @@ -542,27 +542,6 @@ do_assignment(exec_list *instructions, struct _mesa_glsl_parse_state *state, return new(ctx) ir_dereference_variable(var); } - -/** - * Generate a new temporary and add its declaration to the instruction stream - */ -static ir_variable * -generate_temporary(const glsl_type *type, exec_list *instructions, - struct _mesa_glsl_parse_state *state) -{ - void *ctx = state; - char *name = (char *) malloc(sizeof(char) * 13); - - snprintf(name, 13, "tmp_%08X", state->temp_index); - state->temp_index++; - - ir_variable *const var = new(ctx) ir_variable(type, name); - instructions->push_tail(var); - - return var; -} - - static ir_rvalue * get_lvalue_copy(exec_list *instructions, ir_rvalue *lvalue) { @@ -840,8 +819,8 @@ ast_expression::hir(exec_list *instructions, error_emitted = true; } - ir_variable *const tmp = generate_temporary(glsl_type::bool_type, - instructions, state); + ir_variable *const tmp = new(ctx) ir_variable(glsl_type::bool_type, + "and_tmp"); ir_dereference *const then_deref = new(ctx) ir_dereference_variable(tmp); ir_assignment *const then_assign = @@ -892,8 +871,8 @@ ast_expression::hir(exec_list *instructions, ir_if *const stmt = new(ctx) ir_if(op[0]); instructions->push_tail(stmt); - ir_variable *const tmp = generate_temporary(glsl_type::bool_type, - instructions, state); + ir_variable *const tmp = new(ctx) ir_variable(glsl_type::bool_type, + "or_tmp"); op[1] = this->subexpressions[1]->hir(&stmt->then_instructions, state); @@ -1068,8 +1047,7 @@ ast_expression::hir(exec_list *instructions, && (cond_val != NULL) && (then_val != NULL) && (else_val != NULL)) { result = (cond_val->value.b[0]) ? then_val : else_val; } else { - ir_variable *const tmp = generate_temporary(type, - instructions, state); + ir_variable *const tmp = new(ctx) ir_variable(type, "conditional_tmp"); ir_if *const stmt = new(ctx) ir_if(op[0]); instructions->push_tail(stmt); diff --git a/src/glsl/glsl_parser_extras.h b/src/glsl/glsl_parser_extras.h index 16f7268181..4b28ae118d 100644 --- a/src/glsl/glsl_parser_extras.h +++ b/src/glsl/glsl_parser_extras.h @@ -67,9 +67,6 @@ struct _mesa_glsl_parse_state { /** Was there an error during compilation? */ bool error; - /** Index of last generated anonymous temporary. */ - unsigned temp_index; - /** Loop or switch statement containing the current instructions. */ class ir_instruction *loop_or_switch_nesting; diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp index 782934a8d7..dd43d12474 100644 --- a/src/glsl/main.cpp +++ b/src/glsl/main.cpp @@ -124,7 +124,6 @@ compile_shader(struct gl_shader *shader) state->symbols = new(shader) glsl_symbol_table; state->info_log = talloc_strdup(shader, ""); state->error = false; - state->temp_index = 0; state->loop_or_switch_nesting = NULL; state->ARB_texture_rectangle_enable = true; diff --git a/src/mesa/shader/ir_to_mesa.cpp b/src/mesa/shader/ir_to_mesa.cpp index 4496daf2a5..708c6fece1 100644 --- a/src/mesa/shader/ir_to_mesa.cpp +++ b/src/mesa/shader/ir_to_mesa.cpp @@ -1938,7 +1938,6 @@ _mesa_glsl_compile_shader(GLcontext *ctx, struct gl_shader *shader) state->symbols = new(shader) glsl_symbol_table; state->info_log = talloc_strdup(shader, ""); state->error = false; - state->temp_index = 0; state->loop_or_switch_nesting = NULL; state->ARB_texture_rectangle_enable = true; -- cgit v1.2.3 From 3fb878722ed53d79eedb9fe68972ef32b79575d4 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Fri, 9 Jul 2010 14:09:34 -0700 Subject: linker: Stub-out intrastage linker --- src/glsl/linker.cpp | 81 ++++++++++++++++++++++++++++++++++-------- src/glsl/main.cpp | 22 ++++++++++++ src/mesa/shader/ir_to_mesa.cpp | 9 ++--- 3 files changed, 92 insertions(+), 20 deletions(-) (limited to 'src/glsl/main.cpp') diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp index eb10f90a91..e70fa31a2b 100644 --- a/src/glsl/linker.cpp +++ b/src/glsl/linker.cpp @@ -77,9 +77,8 @@ extern "C" { #include "ir.h" #include "ir_optimization.h" #include "program.h" -extern "C" { #include "hash_table.h" -} +#include "shader_api.h" /** * Visitor that determines whether or not a variable is ever written. @@ -399,6 +398,53 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog, } +/** + * Populates a shaders symbol table with all global declarations + */ +static void +populate_symbol_table(gl_shader *sh) +{ + sh->symbols = new(sh) glsl_symbol_table; + + foreach_list(node, sh->ir) { + ir_instruction *const inst = (ir_instruction *) node; + ir_variable *var; + ir_function *func; + + if ((func = inst->as_function()) != NULL) { + sh->symbols->add_function(func->name, func); + } else if ((var = inst->as_variable()) != NULL) { + sh->symbols->add_variable(var->name, var); + } + } +} + + +/** + * Combine a group of shaders for a single stage to generate a linked shader + * + * \note + * If this function is supplied a single shader, it is cloned, and the new + * shader is returned. + */ +static struct gl_shader * +link_intrastage_shaders(struct gl_shader_program *prog, + struct gl_shader **shader_list, + unsigned num_shaders) +{ + (void) prog; + assert(num_shaders == 1); + + gl_shader *const linked = _mesa_new_shader(NULL, 0, shader_list[0]->Type); + linked->ir = new(linked) exec_list; + clone_ir_list(linked->ir, shader_list[0]->ir); + + populate_symbol_table(linked); + + return linked; +} + + struct uniform_node { exec_node link; struct gl_uniform *u; @@ -807,25 +853,32 @@ link_shaders(struct gl_shader_program *prog) } /* FINISHME: Implement intra-stage linking. */ - assert(num_vert_shaders <= 1); - assert(num_frag_shaders <= 1); - - /* Verify that each of the per-target executables is valid. - */ - if (!validate_vertex_shader_executable(prog, vert_shader_list[0]) - || !validate_fragment_shader_executable(prog, frag_shader_list[0])) - goto done; + prog->_NumLinkedShaders = 0; + if (num_vert_shaders > 0) { + gl_shader *const sh = + link_intrastage_shaders(prog, vert_shader_list, num_vert_shaders); + if (sh == NULL) + goto done; - prog->_NumLinkedShaders = 0; + if (!validate_vertex_shader_executable(prog, sh)) + goto done; - if (num_vert_shaders > 0) { - prog->_LinkedShaders[prog->_NumLinkedShaders] = vert_shader_list[0]; + prog->_LinkedShaders[prog->_NumLinkedShaders] = sh; prog->_NumLinkedShaders++; } if (num_frag_shaders > 0) { - prog->_LinkedShaders[prog->_NumLinkedShaders] = frag_shader_list[0]; + gl_shader *const sh = + link_intrastage_shaders(prog, frag_shader_list, num_frag_shaders); + + if (sh == NULL) + goto done; + + if (!validate_fragment_shader_executable(prog, sh)) + goto done; + + prog->_LinkedShaders[prog->_NumLinkedShaders] = sh; prog->_NumLinkedShaders++; } diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp index dd43d12474..8b0bccdcb7 100644 --- a/src/glsl/main.cpp +++ b/src/glsl/main.cpp @@ -36,6 +36,25 @@ #include "ir_print_visitor.h" #include "program.h" +extern "C" struct gl_shader * +_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type); + +/* Copied from shader_api.c for the stand-alone compiler. + */ +struct gl_shader * +_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type) +{ + struct gl_shader *shader; + assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER); + shader = talloc_zero(NULL, struct gl_shader); + if (shader) { + shader->Type = type; + shader->Name = name; + shader->RefCount = 1; + } + return shader; +} + /* Returned string will have 'ctx' as its talloc owner. */ static char * load_text_file(void *ctx, const char *file_name) @@ -271,6 +290,9 @@ main(int argc, char **argv) printf("Info log for linking:\n%s\n", whole_program->InfoLog); } + for (unsigned i = 0; i < whole_program->_NumLinkedShaders; i++) + talloc_free(whole_program->_LinkedShaders[i]); + talloc_free(whole_program); _mesa_glsl_release_types(); diff --git a/src/mesa/shader/ir_to_mesa.cpp b/src/mesa/shader/ir_to_mesa.cpp index c636d69aba..8945e9b3b4 100644 --- a/src/mesa/shader/ir_to_mesa.cpp +++ b/src/mesa/shader/ir_to_mesa.cpp @@ -1998,20 +1998,17 @@ _mesa_glsl_link_shader(GLcontext *ctx, struct gl_shader_program *prog) prog->Uniforms = _mesa_new_uniform_list(); } - prog->LinkStatus = prog->LinkStatus; - - /* FINISHME: This should use the linker-generated code */ if (prog->LinkStatus) { - for (i = 0; i < prog->NumShaders; i++) { + for (i = 0; i < prog->_NumLinkedShaders; i++) { struct gl_program *linked_prog; linked_prog = get_mesa_program(ctx, prog, - prog->Shaders[i]); + prog->_LinkedShaders[i]); count_resources(linked_prog); link_uniforms_to_shared_uniform_list(prog->Uniforms, linked_prog); - switch (prog->Shaders[i]->Type) { + switch (prog->_LinkedShaders[i]->Type) { case GL_VERTEX_SHADER: _mesa_reference_vertprog(ctx, &prog->VertexProgram, (struct gl_vertex_program *)linked_prog); -- cgit v1.2.3 From 25f51d3b9b8c36c41cd23d2797b6a06f6e27ff86 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Fri, 16 Jul 2010 15:51:50 -0700 Subject: linker: Track and validate GLSL versions used in shaders --- src/glsl/linker.cpp | 21 +++++++++++++++++++++ src/glsl/main.cpp | 1 + src/mesa/main/mtypes.h | 4 ++++ src/mesa/shader/ir_to_mesa.cpp | 1 + 4 files changed, 27 insertions(+) (limited to 'src/glsl/main.cpp') diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp index 06aa24e66f..4933686b5e 100644 --- a/src/glsl/linker.cpp +++ b/src/glsl/linker.cpp @@ -66,12 +66,14 @@ #include #include #include +#include extern "C" { #include } #include "main/mtypes.h" +#include "main/macros.h" #include "glsl_symbol_table.h" #include "ir.h" #include "program.h" @@ -1107,7 +1109,12 @@ link_shaders(struct gl_shader_program *prog) calloc(2 * prog->NumShaders, sizeof(struct gl_shader *)); frag_shader_list = &vert_shader_list[prog->NumShaders]; + unsigned min_version = UINT_MAX; + unsigned max_version = 0; for (unsigned i = 0; i < prog->NumShaders; i++) { + min_version = MIN2(min_version, prog->Shaders[i]->Version); + max_version = MAX2(max_version, prog->Shaders[i]->Version); + switch (prog->Shaders[i]->Type) { case GL_VERTEX_SHADER: vert_shader_list[num_vert_shaders] = prog->Shaders[i]; @@ -1124,6 +1131,20 @@ link_shaders(struct gl_shader_program *prog) } } + /* Previous to GLSL version 1.30, different compilation units could mix and + * match shading language versions. With GLSL 1.30 and later, the versions + * of all shaders must match. + */ + assert(min_version >= 110); + assert(max_version <= 130); + if ((max_version >= 130) && (min_version != max_version)) { + linker_error_printf(prog, "all shaders must use same shading " + "language version\n"); + goto done; + } + + prog->Version = max_version; + /* FINISHME: Implement intra-stage linking. */ prog->_NumLinkedShaders = 0; if (num_vert_shaders > 0) { diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp index 8b0bccdcb7..e27d9c1d85 100644 --- a/src/glsl/main.cpp +++ b/src/glsl/main.cpp @@ -207,6 +207,7 @@ compile_shader(struct gl_shader *shader) shader->symbols = state->symbols; shader->CompileStatus = !state->error; + shader->Version = state->language_version; if (shader->InfoLog) talloc_free(shader->InfoLog); diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index be9eaaa875..729c2eaf0f 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -1967,6 +1967,8 @@ struct gl_shader GLchar *InfoLog; struct gl_sl_pragmas Pragmas; + unsigned Version; /**< GLSL version used for linking */ + struct exec_list *ir; struct glsl_symbol_table *symbols; }; @@ -2006,6 +2008,8 @@ struct gl_shader_program GLboolean _Used; /**< Ever used for drawing? */ GLchar *InfoLog; + unsigned Version; /**< GLSL version used for linking */ + /** * Per-stage shaders resulting from the first stage of linking. */ diff --git a/src/mesa/shader/ir_to_mesa.cpp b/src/mesa/shader/ir_to_mesa.cpp index 58320c9217..557f5d319d 100644 --- a/src/mesa/shader/ir_to_mesa.cpp +++ b/src/mesa/shader/ir_to_mesa.cpp @@ -2234,6 +2234,7 @@ _mesa_glsl_compile_shader(GLcontext *ctx, struct gl_shader *shader) shader->CompileStatus = !state->error; shader->InfoLog = state->info_log; + shader->Version = state->language_version; /* Retain any live IR, but trash the rest. */ foreach_list(node, shader->ir) { -- cgit v1.2.3 From 5a2e0b8ce59a3d9f8fa7510546137aff40016c74 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Tue, 20 Jul 2010 11:37:45 -0700 Subject: glsl2: Don't validate IR if there were compilation errors --- src/glsl/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/glsl/main.cpp') diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp index e27d9c1d85..3ae0eebab3 100644 --- a/src/glsl/main.cpp +++ b/src/glsl/main.cpp @@ -172,10 +172,9 @@ compile_shader(struct gl_shader *shader) if (!state->error && !state->translation_unit.is_empty()) _mesa_ast_to_hir(shader->ir, state); - validate_ir_tree(shader->ir); - /* Print out the unoptimized IR. */ if (!state->error && dump_hir) { + validate_ir_tree(shader->ir); _mesa_print_ir(shader->ir, state); } @@ -196,9 +195,10 @@ compile_shader(struct gl_shader *shader) progress = do_vec_index_to_cond_assign(shader->ir) || progress; progress = do_swizzle_swizzle(shader->ir) || progress; } while (progress); + + validate_ir_tree(shader->ir); } - validate_ir_tree(shader->ir); /* Print out the resulting IR */ if (!state->error && dump_lir) { -- cgit v1.2.3 From f8946699ecfa5bc6566821fb855072bbdbd716b2 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 20 Jul 2010 14:03:35 -0700 Subject: glsl2: Add definitions of the builtin constants present in GLSL 1.10. Fixes: glsl1-built-in constants --- src/glsl/glsl_parser_extras.h | 15 ++++++++++++++- src/glsl/ir_variable.cpp | 38 ++++++++++++++++++++++++++++++++------ src/glsl/main.cpp | 19 ++++++++++++++++++- src/mesa/shader/ir_to_mesa.cpp | 14 +++++++++++++- 4 files changed, 77 insertions(+), 9 deletions(-) (limited to 'src/glsl/main.cpp') diff --git a/src/glsl/glsl_parser_extras.h b/src/glsl/glsl_parser_extras.h index 4b28ae118d..fed6e8c823 100644 --- a/src/glsl/glsl_parser_extras.h +++ b/src/glsl/glsl_parser_extras.h @@ -49,8 +49,21 @@ struct _mesa_glsl_parse_state { * \sa struct gl_constants (in mtypes.h) */ struct { - unsigned MaxDrawBuffers; + /* 1.10 */ + unsigned MaxLights; + unsigned MaxClipPlanes; + unsigned MaxTextureUnits; unsigned MaxTextureCoords; + unsigned MaxVertexAttribs; + unsigned MaxVertexUniformComponents; + unsigned MaxVaryingFloats; + unsigned MaxVertexTextureImageUnits; + unsigned MaxCombinedTextureImageUnits; + unsigned MaxTextureImageUnits; + unsigned MaxFragmentUniformComponents; + + /* ARB_draw_buffers */ + unsigned MaxDrawBuffers; } Const; /** diff --git a/src/glsl/ir_variable.cpp b/src/glsl/ir_variable.cpp index a0b66b7770..4593c18112 100644 --- a/src/glsl/ir_variable.cpp +++ b/src/glsl/ir_variable.cpp @@ -93,6 +93,16 @@ add_builtin_variable(const builtin_variable *proto, exec_list *instructions, symtab); } +static void +add_builtin_constant(exec_list *instructions, + struct _mesa_glsl_parse_state *state, + const char *name, int value) +{ + ir_variable *const var = add_variable(name, ir_var_auto, + -1, glsl_type::int_type, + instructions, state->symbols); + var->constant_value = new(var) ir_constant(value); +} static void generate_110_uniforms(exec_list *instructions, @@ -105,12 +115,28 @@ generate_110_uniforms(exec_list *instructions, instructions, state->symbols); } - ir_variable *const mtc = add_variable("gl_MaxTextureCoords", ir_var_auto, - -1, glsl_type::int_type, - instructions, state->symbols); - mtc->constant_value = new(mtc) - ir_constant(int(state->Const.MaxTextureCoords)); - + add_builtin_constant(instructions, state, "gl_MaxLights", + state->Const.MaxLights); + add_builtin_constant(instructions, state, "gl_MaxClipPlanes", + state->Const.MaxClipPlanes); + add_builtin_constant(instructions, state, "gl_MaxTextureUnits", + state->Const.MaxTextureUnits); + add_builtin_constant(instructions, state, "gl_MaxTextureCoords", + state->Const.MaxTextureCoords); + add_builtin_constant(instructions, state, "gl_MaxVertexAttribs", + state->Const.MaxVertexAttribs); + add_builtin_constant(instructions, state, "gl_MaxVertexUniformComponents", + state->Const.MaxVertexUniformComponents); + add_builtin_constant(instructions, state, "gl_MaxVaryingFloats", + state->Const.MaxVaryingFloats); + add_builtin_constant(instructions, state, "gl_MaxVertexTextureImageUnits", + state->Const.MaxVertexTextureImageUnits); + add_builtin_constant(instructions, state, "gl_MaxCombinedTextureImageUnits", + state->Const.MaxCombinedTextureImageUnits); + add_builtin_constant(instructions, state, "gl_MaxTextureImageUnits", + state->Const.MaxTextureImageUnits); + add_builtin_constant(instructions, state, "gl_MaxFragmentUniformComponents", + state->Const.MaxFragmentUniformComponents); const glsl_type *const mat4_array_type = glsl_type::get_array_instance(state->symbols, glsl_type::mat4_type, diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp index 3ae0eebab3..6b1a01c704 100644 --- a/src/glsl/main.cpp +++ b/src/glsl/main.cpp @@ -148,9 +148,26 @@ compile_shader(struct gl_shader *shader) memset(&ext, 0, sizeof(ext)); state->extensions = &ext; - state->Const.MaxDrawBuffers = 2; + /* 1.10 minimums. */ + state->Const.MaxLights = 8; + state->Const.MaxClipPlanes = 8; + state->Const.MaxTextureUnits = 2; + + /* More than the 1.10 minimum to appease parser tests taken from + * apps that (hopefully) already checked the number of coords. + */ state->Const.MaxTextureCoords = 4; + state->Const.MaxVertexAttribs = 16; + state->Const.MaxVertexUniformComponents = 512; + state->Const.MaxVaryingFloats = 32; + state->Const.MaxVertexTextureImageUnits = 0; + state->Const.MaxCombinedTextureImageUnits = 2; + state->Const.MaxTextureImageUnits = 2; + state->Const.MaxFragmentUniformComponents = 64; + + state->Const.MaxDrawBuffers = 2; + const char *source = shader->Source; state->error = preprocess(state, &source, &state->info_log, &ext); diff --git a/src/mesa/shader/ir_to_mesa.cpp b/src/mesa/shader/ir_to_mesa.cpp index 848fb0fb6c..5803960d44 100644 --- a/src/mesa/shader/ir_to_mesa.cpp +++ b/src/mesa/shader/ir_to_mesa.cpp @@ -2170,8 +2170,20 @@ _mesa_glsl_compile_shader(GLcontext *ctx, struct gl_shader *shader) state->ARB_texture_rectangle_enable = true; state->extensions = &ctx->Extensions; - state->Const.MaxDrawBuffers = ctx->Const.MaxDrawBuffers; + + state->Const.MaxLights = ctx->Const.MaxLights; + state->Const.MaxClipPlanes = ctx->Const.MaxClipPlanes; + state->Const.MaxTextureUnits = ctx->Const.MaxTextureUnits; state->Const.MaxTextureCoords = ctx->Const.MaxTextureCoordUnits; + state->Const.MaxVertexAttribs = ctx->Const.VertexProgram.MaxAttribs; + state->Const.MaxVertexUniformComponents = ctx->Const.VertexProgram.MaxUniformComponents; + state->Const.MaxVaryingFloats = ctx->Const.MaxVarying * 4; + state->Const.MaxVertexTextureImageUnits = ctx->Const.MaxVertexTextureImageUnits; + state->Const.MaxCombinedTextureImageUnits = ctx->Const.MaxCombinedTextureImageUnits; + state->Const.MaxTextureImageUnits = ctx->Const.MaxTextureImageUnits; + state->Const.MaxFragmentUniformComponents = ctx->Const.FragmentProgram.MaxUniformComponents; + + state->Const.MaxDrawBuffers = ctx->Const.MaxDrawBuffers; const char *source = shader->Source; state->error = preprocess(state, &source, &state->info_log, -- cgit v1.2.3 From 60e2d06d1ccc66ad00cd7ab81c418853f21be291 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Tue, 20 Jul 2010 11:27:38 -0700 Subject: glsl2: Implement utility routine to talloc reparent an IR tree --- src/glsl/ir.cpp | 15 +++++++++++++++ src/glsl/ir.h | 3 +++ src/glsl/main.cpp | 10 +--------- src/mesa/shader/ir_to_mesa.cpp | 10 +--------- 4 files changed, 20 insertions(+), 18 deletions(-) (limited to 'src/glsl/main.cpp') diff --git a/src/glsl/ir.cpp b/src/glsl/ir.cpp index 146ff17af3..a2732962f0 100644 --- a/src/glsl/ir.cpp +++ b/src/glsl/ir.cpp @@ -875,3 +875,18 @@ visit_exec_list(exec_list *list, ir_visitor *visitor) } } + +static void +steal_memory(ir_instruction *ir, void *new_ctx) +{ + talloc_steal(new_ctx, ir); +} + + +void +reparent_ir(exec_list *list, void *mem_ctx) +{ + foreach_list(node, list) { + visit_tree((ir_instruction *) node, steal_memory, mem_ctx); + } +} diff --git a/src/glsl/ir.h b/src/glsl/ir.h index 9fd9850391..e4b0e9f082 100644 --- a/src/glsl/ir.h +++ b/src/glsl/ir.h @@ -1315,4 +1315,7 @@ extern void _mesa_glsl_initialize_functions(exec_list *instructions, struct _mesa_glsl_parse_state *state); +extern void +reparent_ir(exec_list *list, void *mem_ctx); + #endif /* IR_H */ diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp index 6b1a01c704..cf9a515785 100644 --- a/src/glsl/main.cpp +++ b/src/glsl/main.cpp @@ -118,12 +118,6 @@ const struct option compiler_opts[] = { { NULL, 0, NULL, 0 } }; -static void -steal_memory(ir_instruction *ir, void *new_ctx) -{ - talloc_steal(new_ctx, ir); -} - void compile_shader(struct gl_shader *shader) { @@ -232,9 +226,7 @@ compile_shader(struct gl_shader *shader) shader->InfoLog = state->info_log; /* Retain any live IR, but trash the rest. */ - foreach_list(node, shader->ir) { - visit_tree((ir_instruction *) node, steal_memory, shader); - } + reparent_ir(shader->ir, shader); talloc_free(state); diff --git a/src/mesa/shader/ir_to_mesa.cpp b/src/mesa/shader/ir_to_mesa.cpp index 1a9b0e3948..d1c09febd6 100644 --- a/src/mesa/shader/ir_to_mesa.cpp +++ b/src/mesa/shader/ir_to_mesa.cpp @@ -2146,12 +2146,6 @@ get_mesa_program(GLcontext *ctx, struct gl_shader_program *shader_program, extern "C" { -static void -steal_memory(ir_instruction *ir, void *new_ctx) -{ - talloc_steal(new_ctx, ir); -} - void _mesa_glsl_compile_shader(GLcontext *ctx, struct gl_shader *shader) { @@ -2215,9 +2209,7 @@ _mesa_glsl_compile_shader(GLcontext *ctx, struct gl_shader *shader) shader->Version = state->language_version; /* Retain any live IR, but trash the rest. */ - foreach_list(node, shader->ir) { - visit_tree((ir_instruction *) node, steal_memory, shader); - } + reparent_ir(shader->ir, shader); talloc_free(state); } -- cgit v1.2.3 From d5be2acae379783c4aa31243e0a88a9e67e6ca7e Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Tue, 20 Jul 2010 11:29:46 -0700 Subject: linker: Link built-in functions instead of including them in every shader This is an invasive set of changes. Each user shader tracks a set of other shaders that contain built-in functions. During compilation, function prototypes are imported from these shaders. During linking, the shaders are linked with these built-in-function shaders just like with any other shader. --- src/glsl/builtin_function.cpp | 218 ++++++++++++++++++++------- src/glsl/builtins/110_vs/ftransform | 4 +- src/glsl/builtins/tools/generate_builtins.pl | 63 ++++++-- src/glsl/glsl_parser_extras.h | 4 + src/glsl/ir.h | 3 + src/glsl/linker.cpp | 23 ++- src/glsl/main.cpp | 4 + src/mesa/main/mtypes.h | 4 + src/mesa/shader/ir_to_mesa.cpp | 3 + 9 files changed, 261 insertions(+), 65 deletions(-) (limited to 'src/glsl/main.cpp') diff --git a/src/glsl/builtin_function.cpp b/src/glsl/builtin_function.cpp index 967bcd0c40..10e59e491e 100644 --- a/src/glsl/builtin_function.cpp +++ b/src/glsl/builtin_function.cpp @@ -25,22 +25,41 @@ #include #include "glsl_parser_extras.h" #include "ir_reader.h" +#include "program.h" -void -read_builtins(_mesa_glsl_parse_state *st, exec_list *instructions, - const char **functions, unsigned count) +extern "C" struct gl_shader * +_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type); + +gl_shader * +read_builtins(GLenum target, const char **functions, unsigned count) { - if (st->error) - return; + gl_shader *sh = _mesa_new_shader(NULL, 0, target); + struct _mesa_glsl_parse_state *st = + new(sh) _mesa_glsl_parse_state(NULL, target, sh); + + st->language_version = 130; + st->ARB_texture_rectangle_enable = true; + st->EXT_texture_array_enable = true; + _mesa_glsl_initialize_types(st); + + sh->ir = new(sh) exec_list; + sh->symbols = st->symbols; for (unsigned i = 0; i < count; i++) { - _mesa_glsl_read_ir(st, instructions, functions[i]); + _mesa_glsl_read_ir(st, sh->ir, functions[i]); if (st->error) { printf("error reading builtin: %.35s ...\n", functions[i]); - return; + delete st; + talloc_free(sh); + return NULL; } } + + reparent_ir(sh->ir, sh); + delete st; + + return sh; } /* 110 builtins */ @@ -2580,7 +2599,9 @@ static const char *functions_for_110_fs [] = { /* 110_vs builtins */ static const char *builtins_110_vs_ftransform = { - "((function ftransform\n" + "((declare (uniform) mat4 gl_ModelViewProjectionMatrix)\n" + " (declare (in) vec4 gl_Vertex)\n" + " (function ftransform\n" " (signature vec4\n" " (parameters)\n" " ((return (expression vec4 *\n" @@ -4760,53 +4781,146 @@ static const char *functions_for_EXT_texture_array_fs [] = { #define Elements(x) (sizeof(x)/sizeof(*(x))) #endif +void *builtin_mem_ctx = NULL; + +void +_mesa_glsl_release_functions(void) +{ + talloc_free(builtin_mem_ctx); +} + void _mesa_glsl_initialize_functions(exec_list *instructions, struct _mesa_glsl_parse_state *state) { - if (state->language_version >= 110) - read_builtins(state, instructions, - functions_for_110, - Elements(functions_for_110)); - - if (state->target == fragment_shader && state->language_version >= 110) - read_builtins(state, instructions, - functions_for_110_fs, - Elements(functions_for_110_fs)); - - if (state->target == vertex_shader && state->language_version >= 110) - read_builtins(state, instructions, - functions_for_110_vs, - Elements(functions_for_110_vs)); - - if (state->language_version >= 120) - read_builtins(state, instructions, - functions_for_120, - Elements(functions_for_120)); - - if (state->language_version >= 130) - read_builtins(state, instructions, - functions_for_130, - Elements(functions_for_130)); - - if (state->target == fragment_shader && state->language_version >= 130) - read_builtins(state, instructions, - functions_for_130_fs, - Elements(functions_for_130_fs)); - - if (state->ARB_texture_rectangle_enable) - read_builtins(state, instructions, - functions_for_ARB_texture_rectangle, - Elements(functions_for_ARB_texture_rectangle)); - - if (state->EXT_texture_array_enable) - read_builtins(state, instructions, - functions_for_EXT_texture_array, - Elements(functions_for_EXT_texture_array)); - - if (state->target == fragment_shader && state->EXT_texture_array_enable) - read_builtins(state, instructions, - functions_for_EXT_texture_array_fs, - Elements(functions_for_EXT_texture_array_fs)); + if (builtin_mem_ctx == NULL) + builtin_mem_ctx = talloc_init("GLSL built-in functions"); + + state->num_builtins_to_link = 0; + if (state->language_version >= 110) { + static gl_shader *sh = NULL; + + if (sh == NULL) { + sh = read_builtins(GL_VERTEX_SHADER, functions_for_110, + Elements(functions_for_110)); + talloc_steal(builtin_mem_ctx, sh); + } + + import_prototypes(sh->ir, instructions, state->symbols, state); + state->builtins_to_link[state->num_builtins_to_link] = sh; + state->num_builtins_to_link++; + } + + if (state->target == fragment_shader && state->language_version >= 110) { + static gl_shader *sh = NULL; + + if (sh == NULL) { + sh = read_builtins(GL_VERTEX_SHADER, functions_for_110_fs, + Elements(functions_for_110_fs)); + talloc_steal(builtin_mem_ctx, sh); + } + + import_prototypes(sh->ir, instructions, state->symbols, state); + state->builtins_to_link[state->num_builtins_to_link] = sh; + state->num_builtins_to_link++; + } + + if (state->target == vertex_shader && state->language_version >= 110) { + static gl_shader *sh = NULL; + + if (sh == NULL) { + sh = read_builtins(GL_VERTEX_SHADER, functions_for_110_vs, + Elements(functions_for_110_vs)); + talloc_steal(builtin_mem_ctx, sh); + } + + import_prototypes(sh->ir, instructions, state->symbols, state); + state->builtins_to_link[state->num_builtins_to_link] = sh; + state->num_builtins_to_link++; + } + + if (state->language_version >= 120) { + static gl_shader *sh = NULL; + + if (sh == NULL) { + sh = read_builtins(GL_VERTEX_SHADER, functions_for_120, + Elements(functions_for_120)); + talloc_steal(builtin_mem_ctx, sh); + } + + import_prototypes(sh->ir, instructions, state->symbols, state); + state->builtins_to_link[state->num_builtins_to_link] = sh; + state->num_builtins_to_link++; + } + + if (state->language_version >= 130) { + static gl_shader *sh = NULL; + + if (sh == NULL) { + sh = read_builtins(GL_VERTEX_SHADER, functions_for_130, + Elements(functions_for_130)); + talloc_steal(builtin_mem_ctx, sh); + } + + import_prototypes(sh->ir, instructions, state->symbols, state); + state->builtins_to_link[state->num_builtins_to_link] = sh; + state->num_builtins_to_link++; + } + + if (state->target == fragment_shader && state->language_version >= 130) { + static gl_shader *sh = NULL; + + if (sh == NULL) { + sh = read_builtins(GL_VERTEX_SHADER, functions_for_130_fs, + Elements(functions_for_130_fs)); + talloc_steal(builtin_mem_ctx, sh); + } + + import_prototypes(sh->ir, instructions, state->symbols, state); + state->builtins_to_link[state->num_builtins_to_link] = sh; + state->num_builtins_to_link++; + } + + if (state->ARB_texture_rectangle_enable) { + static gl_shader *sh = NULL; + + if (sh == NULL) { + sh = read_builtins(GL_VERTEX_SHADER, functions_for_ARB_texture_rectangle, + Elements(functions_for_ARB_texture_rectangle)); + talloc_steal(builtin_mem_ctx, sh); + } + + import_prototypes(sh->ir, instructions, state->symbols, state); + state->builtins_to_link[state->num_builtins_to_link] = sh; + state->num_builtins_to_link++; + } + + if (state->EXT_texture_array_enable) { + static gl_shader *sh = NULL; + + if (sh == NULL) { + sh = read_builtins(GL_VERTEX_SHADER, functions_for_EXT_texture_array, + Elements(functions_for_EXT_texture_array)); + talloc_steal(builtin_mem_ctx, sh); + } + + import_prototypes(sh->ir, instructions, state->symbols, state); + state->builtins_to_link[state->num_builtins_to_link] = sh; + state->num_builtins_to_link++; + } + + if (state->target == fragment_shader && state->EXT_texture_array_enable) { + static gl_shader *sh = NULL; + + if (sh == NULL) { + sh = read_builtins(GL_VERTEX_SHADER, functions_for_EXT_texture_array_fs, + Elements(functions_for_EXT_texture_array_fs)); + talloc_steal(builtin_mem_ctx, sh); + } + + import_prototypes(sh->ir, instructions, state->symbols, state); + state->builtins_to_link[state->num_builtins_to_link] = sh; + state->num_builtins_to_link++; + } } diff --git a/src/glsl/builtins/110_vs/ftransform b/src/glsl/builtins/110_vs/ftransform index 3a5e8ccecf..9ca63dc1e3 100644 --- a/src/glsl/builtins/110_vs/ftransform +++ b/src/glsl/builtins/110_vs/ftransform @@ -1,4 +1,6 @@ -((function ftransform +((declare (uniform) mat4 gl_ModelViewProjectionMatrix) + (declare (in) vec4 gl_Vertex) + (function ftransform (signature vec4 (parameters) ((return (expression vec4 * diff --git a/src/glsl/builtins/tools/generate_builtins.pl b/src/glsl/builtins/tools/generate_builtins.pl index a0b5c1f421..61d511da1d 100755 --- a/src/glsl/builtins/tools/generate_builtins.pl +++ b/src/glsl/builtins/tools/generate_builtins.pl @@ -64,22 +64,41 @@ print << 'EOF'; #include #include "glsl_parser_extras.h" #include "ir_reader.h" +#include "program.h" -void -read_builtins(_mesa_glsl_parse_state *st, exec_list *instructions, - const char **functions, unsigned count) +extern "C" struct gl_shader * +_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type); + +gl_shader * +read_builtins(GLenum target, const char **functions, unsigned count) { - if (st->error) - return; + gl_shader *sh = _mesa_new_shader(NULL, 0, target); + struct _mesa_glsl_parse_state *st = + new(sh) _mesa_glsl_parse_state(NULL, target, sh); + + st->language_version = 130; + st->ARB_texture_rectangle_enable = true; + st->EXT_texture_array_enable = true; + _mesa_glsl_initialize_types(st); + + sh->ir = new(sh) exec_list; + sh->symbols = st->symbols; for (unsigned i = 0; i < count; i++) { - _mesa_glsl_read_ir(st, instructions, functions[i]); + _mesa_glsl_read_ir(st, sh->ir, functions[i]); if (st->error) { printf("error reading builtin: %.35s ...\n", functions[i]); - return; + delete st; + talloc_free(sh); + return NULL; } } + + reparent_ir(sh->ir, sh); + delete st; + + return sh; } EOF @@ -95,10 +114,22 @@ print << 'EOF'; #define Elements(x) (sizeof(x)/sizeof(*(x))) #endif +void *builtin_mem_ctx = NULL; + +void +_mesa_glsl_release_functions(void) +{ + talloc_free(builtin_mem_ctx); +} + void _mesa_glsl_initialize_functions(exec_list *instructions, struct _mesa_glsl_parse_state *state) { + if (builtin_mem_ctx == NULL) + builtin_mem_ctx = talloc_init("GLSL built-in functions"); + + state->num_builtins_to_link = 0; EOF foreach $version_xs (@versions) { @@ -117,10 +148,20 @@ foreach $version_xs (@versions) { # Not a version...an extension name $check = "${check}state->${version}_enable"; } - print " if ($check)\n"; - print " read_builtins(state, instructions,\n"; - print " functions_for_$version_xs,\n"; - print " Elements(functions_for_$version_xs));\n\n" + print " if ($check) {\n"; + print " static gl_shader *sh = NULL;\n"; + print "\n"; + print " if (sh == NULL) {\n"; + print " sh = read_builtins(GL_VERTEX_SHADER, functions_for_$version_xs,\n"; + print " Elements(functions_for_$version_xs));\n"; + print " talloc_steal(builtin_mem_ctx, sh);\n"; + print " }\n"; + print "\n"; + print " import_prototypes(sh->ir, instructions, state->symbols, state);\n"; + print " state->builtins_to_link[state->num_builtins_to_link] = sh;\n"; + print " state->num_builtins_to_link++;\n"; + print " }\n"; + print "\n"; } print "}\n"; diff --git a/src/glsl/glsl_parser_extras.h b/src/glsl/glsl_parser_extras.h index b50d9eea67..56f6e18e0b 100644 --- a/src/glsl/glsl_parser_extras.h +++ b/src/glsl/glsl_parser_extras.h @@ -125,6 +125,10 @@ struct _mesa_glsl_parse_state { /** Extensions supported by the OpenGL implementation. */ const struct gl_extensions *extensions; + + /** Shaders containing built-in functions that are used for linking. */ + struct gl_shader *builtins_to_link[16]; + unsigned num_builtins_to_link; }; typedef struct YYLTYPE { diff --git a/src/glsl/ir.h b/src/glsl/ir.h index 38b10f5b06..3a643fc580 100644 --- a/src/glsl/ir.h +++ b/src/glsl/ir.h @@ -1315,6 +1315,9 @@ extern void _mesa_glsl_initialize_functions(exec_list *instructions, struct _mesa_glsl_parse_state *state); +extern void +_mesa_glsl_release_functions(void); + extern void reparent_ir(exec_list *list, void *mem_ctx); diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp index 640e6eee8e..7c30a40a6c 100644 --- a/src/glsl/linker.cpp +++ b/src/glsl/linker.cpp @@ -739,7 +739,28 @@ link_intrastage_shaders(struct gl_shader_program *prog, /* Resolve initializers for global variables in the linked shader. */ - link_function_calls(prog, linked, shader_list, num_shaders); + unsigned num_linking_shaders = num_shaders; + for (unsigned i = 0; i < num_shaders; i++) + num_linking_shaders += shader_list[i]->num_builtins_to_link; + + gl_shader **linking_shaders = + (gl_shader **) calloc(num_linking_shaders, sizeof(gl_shader *)); + + memcpy(linking_shaders, shader_list, + sizeof(linking_shaders[0]) * num_shaders); + + unsigned idx = num_shaders; + for (unsigned i = 0; i < num_shaders; i++) { + memcpy(&linking_shaders[idx], shader_list[i]->builtins_to_link, + sizeof(linking_shaders[0]) * shader_list[i]->num_builtins_to_link); + idx += shader_list[i]->num_builtins_to_link; + } + + assert(idx == num_linking_shaders); + + link_function_calls(prog, linked, linking_shaders, num_linking_shaders); + + free(linking_shaders); return linked; } diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp index cf9a515785..2ecf57f8ce 100644 --- a/src/glsl/main.cpp +++ b/src/glsl/main.cpp @@ -219,6 +219,9 @@ compile_shader(struct gl_shader *shader) shader->symbols = state->symbols; shader->CompileStatus = !state->error; shader->Version = state->language_version; + memcpy(shader->builtins_to_link, state->builtins_to_link, + sizeof(shader->builtins_to_link[0]) * state->num_builtins_to_link); + shader->num_builtins_to_link = state->num_builtins_to_link; if (shader->InfoLog) talloc_free(shader->InfoLog); @@ -305,6 +308,7 @@ main(int argc, char **argv) talloc_free(whole_program); _mesa_glsl_release_types(); + _mesa_glsl_release_functions(); return status; } diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index 729c2eaf0f..f8257d565b 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -1971,6 +1971,10 @@ struct gl_shader struct exec_list *ir; struct glsl_symbol_table *symbols; + + /** Shaders containing built-in functions that are used for linking. */ + struct gl_shader *builtins_to_link[16]; + unsigned num_builtins_to_link; }; diff --git a/src/mesa/shader/ir_to_mesa.cpp b/src/mesa/shader/ir_to_mesa.cpp index a2b2eb95c8..bfb8e3201a 100644 --- a/src/mesa/shader/ir_to_mesa.cpp +++ b/src/mesa/shader/ir_to_mesa.cpp @@ -2207,6 +2207,9 @@ _mesa_glsl_compile_shader(GLcontext *ctx, struct gl_shader *shader) shader->CompileStatus = !state->error; shader->InfoLog = state->info_log; shader->Version = state->language_version; + memcpy(shader->builtins_to_link, state->builtins_to_link, + sizeof(shader->builtins_to_link[0]) * state->num_builtins_to_link); + shader->num_builtins_to_link = state->num_builtins_to_link; /* Retain any live IR, but trash the rest. */ reparent_ir(shader->ir, shader); -- cgit v1.2.3 From aa9f86ae8b3bb2172092ff9b50751677c509e6b4 Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Thu, 22 Jul 2010 16:20:36 -0700 Subject: glsl2: Fix standalone compiler to not crash horribly. ir_to_mesa was updated for the _mesa_glsl_parse_state constructor changes, but main.cpp was not. --- src/glsl/glsl_parser_extras.cpp | 23 +++++++++++++++++++++ src/glsl/main.cpp | 45 ++++------------------------------------- 2 files changed, 27 insertions(+), 41 deletions(-) (limited to 'src/glsl/main.cpp') diff --git a/src/glsl/glsl_parser_extras.cpp b/src/glsl/glsl_parser_extras.cpp index bcf2579733..009aabcd35 100644 --- a/src/glsl/glsl_parser_extras.cpp +++ b/src/glsl/glsl_parser_extras.cpp @@ -68,10 +68,33 @@ _mesa_glsl_parse_state::_mesa_glsl_parse_state(struct __GLcontextRec *ctx, this->Const.MaxDrawBuffers = ctx->Const.MaxDrawBuffers; } else { + /* If there is no GL context (standalone compiler), fill in constants + * with the minimum required values. + */ static struct gl_extensions null_extensions; memset(&null_extensions, 0, sizeof(null_extensions)); this->extensions = &null_extensions; + + /* 1.10 minimums. */ + this->Const.MaxLights = 8; + this->Const.MaxClipPlanes = 8; + this->Const.MaxTextureUnits = 2; + + /* More than the 1.10 minimum to appease parser tests taken from + * apps that (hopefully) already checked the number of coords. + */ + this->Const.MaxTextureCoords = 4; + + this->Const.MaxVertexAttribs = 16; + this->Const.MaxVertexUniformComponents = 512; + this->Const.MaxVaryingFloats = 32; + this->Const.MaxVertexTextureImageUnits = 0; + this->Const.MaxCombinedTextureImageUnits = 2; + this->Const.MaxTextureImageUnits = 2; + this->Const.MaxFragmentUniformComponents = 64; + + this->Const.MaxDrawBuffers = 2; } } diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp index 2ecf57f8ce..5c0f6475e0 100644 --- a/src/glsl/main.cpp +++ b/src/glsl/main.cpp @@ -121,49 +121,12 @@ const struct option compiler_opts[] = { void compile_shader(struct gl_shader *shader) { - struct _mesa_glsl_parse_state *state; - struct gl_extensions ext; - - state = talloc_zero(talloc_parent(shader), struct _mesa_glsl_parse_state); - - switch (shader->Type) { - case GL_VERTEX_SHADER: state->target = vertex_shader; break; - case GL_FRAGMENT_SHADER: state->target = fragment_shader; break; - case GL_GEOMETRY_SHADER: state->target = geometry_shader; break; - } - - state->scanner = NULL; - state->translation_unit.make_empty(); - state->symbols = new(shader) glsl_symbol_table; - state->info_log = talloc_strdup(shader, ""); - state->error = false; - state->loop_or_switch_nesting = NULL; - state->ARB_texture_rectangle_enable = true; - - memset(&ext, 0, sizeof(ext)); - state->extensions = &ext; - /* 1.10 minimums. */ - state->Const.MaxLights = 8; - state->Const.MaxClipPlanes = 8; - state->Const.MaxTextureUnits = 2; - - /* More than the 1.10 minimum to appease parser tests taken from - * apps that (hopefully) already checked the number of coords. - */ - state->Const.MaxTextureCoords = 4; - - state->Const.MaxVertexAttribs = 16; - state->Const.MaxVertexUniformComponents = 512; - state->Const.MaxVaryingFloats = 32; - state->Const.MaxVertexTextureImageUnits = 0; - state->Const.MaxCombinedTextureImageUnits = 2; - state->Const.MaxTextureImageUnits = 2; - state->Const.MaxFragmentUniformComponents = 64; - - state->Const.MaxDrawBuffers = 2; + struct _mesa_glsl_parse_state *state = + new(shader) _mesa_glsl_parse_state(NULL, shader->Type, shader); const char *source = shader->Source; - state->error = preprocess(state, &source, &state->info_log, &ext); + state->error = preprocess(state, &source, &state->info_log, + state->extensions); if (!state->error) { _mesa_glsl_lexer_ctor(state, source); -- cgit v1.2.3 From 832aad989e3d319a8aaac046aa49df25da134d82 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 26 Jul 2010 22:50:29 -0700 Subject: glsl2: Add optimization pass for algebraic simplifications. This cleans up the assembly output of almost all the non-logic tests glsl-algebraic-*. glsl-algebraic-pow-two needs love (basically, flattening to a temporary and squaring it). --- src/glsl/Makefile | 1 + src/glsl/ir.h | 8 + src/glsl/ir_algebraic.cpp | 366 ++++++++++++++++++++++++++++++++++++++++ src/glsl/ir_optimization.h | 3 +- src/glsl/main.cpp | 1 + src/mesa/program/ir_to_mesa.cpp | 1 + 6 files changed, 379 insertions(+), 1 deletion(-) create mode 100644 src/glsl/ir_algebraic.cpp (limited to 'src/glsl/main.cpp') diff --git a/src/glsl/Makefile b/src/glsl/Makefile index 462d49e884..4c85af8906 100644 --- a/src/glsl/Makefile +++ b/src/glsl/Makefile @@ -30,6 +30,7 @@ CXX_SOURCES = \ glsl_parser_extras.cpp \ glsl_types.cpp \ hir_field_selection.cpp \ + ir_algebraic.cpp \ ir_basic_block.cpp \ ir_clone.cpp \ ir_constant_expression.cpp \ diff --git a/src/glsl/ir.h b/src/glsl/ir.h index e0f3683a7a..7e8363106d 100644 --- a/src/glsl/ir.h +++ b/src/glsl/ir.h @@ -613,7 +613,15 @@ enum ir_expression_operation { ir_binop_greater, ir_binop_lequal, ir_binop_gequal, + /** + * Returns single boolean for whether all components of operands[0] + * equal the components of operands[1]. + */ ir_binop_equal, + /** + * Returns single boolean for whether any component of operands[0] + * is not equal to the corresponding component of operands[1]. + */ ir_binop_nequal, /*@}*/ diff --git a/src/glsl/ir_algebraic.cpp b/src/glsl/ir_algebraic.cpp new file mode 100644 index 0000000000..5b065b086e --- /dev/null +++ b/src/glsl/ir_algebraic.cpp @@ -0,0 +1,366 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_algebraic.cpp + * + * Takes advantage of association, commutivity, and other algebraic + * properties to simplify expressions. + */ + +#include "ir.h" +#include "ir_visitor.h" +#include "ir_optimization.h" +#include "glsl_types.h" + +/** + * Visitor class for replacing expressions with ir_constant values. + */ + +class ir_algebraic_visitor : public ir_hierarchical_visitor { +public: + ir_algebraic_visitor() + { + this->progress = false; + } + + virtual ~ir_algebraic_visitor() + { + } + + virtual ir_visitor_status visit_leave(ir_assignment *); + virtual ir_visitor_status visit_leave(ir_call *); + virtual ir_visitor_status visit_leave(ir_dereference_array *); + virtual ir_visitor_status visit_leave(ir_expression *); + virtual ir_visitor_status visit_leave(ir_if *); + virtual ir_visitor_status visit_leave(ir_return *); + virtual ir_visitor_status visit_leave(ir_swizzle *); + virtual ir_visitor_status visit_leave(ir_texture *); + + ir_rvalue *handle_expression(ir_rvalue *in_ir); + + bool progress; +}; + +static bool +is_vec_zero(ir_constant *ir) +{ + int c; + + if (!ir) + return false; + if (!ir->type->is_scalar() && + !ir->type->is_vector()) + return false; + + for (c = 0; c < ir->type->vector_elements; c++) { + switch (ir->type->base_type) { + case GLSL_TYPE_FLOAT: + if (ir->value.f[c] != 0.0) + return false; + break; + case GLSL_TYPE_INT: + if (ir->value.i[c] != 0) + return false; + break; + case GLSL_TYPE_UINT: + if (ir->value.u[c] != 0) + return false; + break; + case GLSL_TYPE_BOOL: + if (ir->value.b[c] != false) + return false; + break; + default: + assert(!"bad base type"); + return false; + } + } + + return true; +} + +static bool +is_vec_one(ir_constant *ir) +{ + int c; + + if (!ir) + return false; + if (!ir->type->is_scalar() && + !ir->type->is_vector()) + return false; + + for (c = 0; c < ir->type->vector_elements; c++) { + switch (ir->type->base_type) { + case GLSL_TYPE_FLOAT: + if (ir->value.f[c] != 1.0) + return false; + break; + case GLSL_TYPE_INT: + if (ir->value.i[c] != 1) + return false; + break; + case GLSL_TYPE_UINT: + if (ir->value.u[c] != 1) + return false; + break; + case GLSL_TYPE_BOOL: + if (ir->value.b[c] != true) + return false; + break; + default: + assert(!"bad base type"); + return false; + } + } + + return true; +} + +ir_rvalue * +ir_algebraic_visitor::handle_expression(ir_rvalue *in_ir) +{ + ir_expression *ir = (ir_expression *)in_ir; + ir_constant *op_const[2] = {NULL, NULL}; + ir_expression *op_expr[2] = {NULL, NULL}; + unsigned int i; + + if (!in_ir) + return NULL; + + if (in_ir->ir_type != ir_type_expression) + return in_ir; + + for (i = 0; i < ir->get_num_operands(); i++) { + if (ir->operands[i]->type->is_matrix()) + return in_ir; + + op_const[i] = ir->operands[i]->constant_expression_value(); + op_expr[i] = ir->operands[i]->as_expression(); + } + + switch (ir->operation) { + case ir_unop_logic_not: + if (op_expr[0] && op_expr[0]->operation == ir_binop_equal) { + this->progress = true; + return new(ir) ir_expression(ir_binop_nequal, + ir->type, + op_expr[0]->operands[0], + op_expr[0]->operands[1]); + } + if (op_expr[0] && op_expr[0]->operation == ir_binop_nequal) { + this->progress = true; + return new(ir) ir_expression(ir_binop_equal, + ir->type, + op_expr[0]->operands[0], + op_expr[0]->operands[1]); + } + break; + + case ir_binop_add: + if (is_vec_zero(op_const[0])) { + this->progress = true; + return ir->operands[1]; + } + if (is_vec_zero(op_const[1])) { + this->progress = true; + return ir->operands[0]; + } + break; + + case ir_binop_sub: + if (is_vec_zero(op_const[0])) { + this->progress = true; + return new(ir) ir_expression(ir_unop_neg, + ir->type, + ir->operands[1], + NULL); + } + if (is_vec_zero(op_const[1])) { + this->progress = true; + return ir->operands[0]; + } + break; + + case ir_binop_mul: + if (is_vec_one(op_const[0])) { + this->progress = true; + return ir->operands[1]; + } + if (is_vec_one(op_const[1])) { + this->progress = true; + return ir->operands[0]; + } + + if (is_vec_zero(op_const[0]) || + is_vec_zero(op_const[1])) { + ir_constant_data zero_data; + memset(&zero_data, 0, sizeof(zero_data)); + + this->progress = true; + return new(ir) ir_constant(ir->type, &zero_data); + } + break; + + case ir_binop_div: + if (is_vec_one(op_const[0]) && ir->type->base_type == GLSL_TYPE_FLOAT) { + this->progress = true; + return new(ir) ir_expression(ir_unop_rcp, + ir->type, + ir->operands[1], + NULL); + } + if (is_vec_one(op_const[1])) { + this->progress = true; + return ir->operands[0]; + } + break; + + case ir_unop_rcp: + if (op_expr[0] && op_expr[0]->operation == ir_unop_rcp) { + this->progress = true; + return op_expr[0]->operands[0]; + } + + /* FINISHME: We should do rcp(rsq(x)) -> sqrt(x) for some + * backends, except that some backends will have done sqrt -> + * rcp(rsq(x)) and we don't want to undo it for them. + */ + + /* As far as we know, all backends are OK with rsq. */ + if (op_expr[0] && op_expr[0]->operation == ir_unop_sqrt) { + this->progress = true; + return new(ir) ir_expression(ir_unop_rsq, + ir->type, + op_expr[0]->operands[0], + NULL); + } + + break; + + default: + break; + } + + return in_ir; +} + +ir_visitor_status +ir_algebraic_visitor::visit_leave(ir_expression *ir) +{ + unsigned int operand; + + for (operand = 0; operand < ir->get_num_operands(); operand++) { + ir->operands[operand] = handle_expression(ir->operands[operand]); + } + + return visit_continue; +} + +ir_visitor_status +ir_algebraic_visitor::visit_leave(ir_texture *ir) +{ + ir->coordinate = handle_expression(ir->coordinate); + ir->projector = handle_expression(ir->projector); + ir->shadow_comparitor = handle_expression(ir->shadow_comparitor); + + switch (ir->op) { + case ir_tex: + break; + case ir_txb: + ir->lod_info.bias = handle_expression(ir->lod_info.bias); + break; + case ir_txf: + case ir_txl: + ir->lod_info.lod = handle_expression(ir->lod_info.lod); + break; + case ir_txd: + ir->lod_info.grad.dPdx = handle_expression(ir->lod_info.grad.dPdx); + ir->lod_info.grad.dPdy = handle_expression(ir->lod_info.grad.dPdy); + break; + } + + return visit_continue; +} + +ir_visitor_status +ir_algebraic_visitor::visit_leave(ir_swizzle *ir) +{ + ir->val = handle_expression(ir->val); + return visit_continue; +} + +ir_visitor_status +ir_algebraic_visitor::visit_leave(ir_dereference_array *ir) +{ + ir->array_index = handle_expression(ir->array_index); + return visit_continue; +} + +ir_visitor_status +ir_algebraic_visitor::visit_leave(ir_assignment *ir) +{ + ir->rhs = handle_expression(ir->rhs); + ir->condition = handle_expression(ir->condition); + return visit_continue; +} + +ir_visitor_status +ir_algebraic_visitor::visit_leave(ir_call *ir) +{ + foreach_iter(exec_list_iterator, iter, *ir) { + ir_rvalue *param = (ir_rvalue *)iter.get(); + ir_rvalue *new_param = handle_expression(param); + + if (new_param != param) { + param->replace_with(new_param); + } + } + return visit_continue; +} + +ir_visitor_status +ir_algebraic_visitor::visit_leave(ir_return *ir) +{ + ir->value = handle_expression(ir->value);; + return visit_continue; +} + +ir_visitor_status +ir_algebraic_visitor::visit_leave(ir_if *ir) +{ + ir->condition = handle_expression(ir->condition); + return visit_continue; +} + + +bool +do_algebraic(exec_list *instructions) +{ + ir_algebraic_visitor v; + + visit_list_elements(&v, instructions); + + return v.progress; +} diff --git a/src/glsl/ir_optimization.h b/src/glsl/ir_optimization.h index 06cb4d22ca..4f39565e5f 100644 --- a/src/glsl/ir_optimization.h +++ b/src/glsl/ir_optimization.h @@ -23,11 +23,12 @@ /** - * \file ir_dead_code.h + * \file ir_optimization.h * * Prototypes for optimization passes to be called by the compiler and drivers. */ +bool do_algebraic(exec_list *instructions); bool do_constant_folding(exec_list *instructions); bool do_constant_variable(exec_list *instructions); bool do_constant_variable_unlinked(exec_list *instructions); diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp index 5c0f6475e0..b62902278c 100644 --- a/src/glsl/main.cpp +++ b/src/glsl/main.cpp @@ -165,6 +165,7 @@ compile_shader(struct gl_shader *shader) progress = do_dead_code_unlinked(state, shader->ir) || progress; progress = do_constant_variable_unlinked(shader->ir) || progress; progress = do_constant_folding(shader->ir) || progress; + progress = do_algebraic(shader->ir) || progress; progress = do_vec_index_to_swizzle(shader->ir) || progress; progress = do_vec_index_to_cond_assign(shader->ir) || progress; progress = do_swizzle_swizzle(shader->ir) || progress; diff --git a/src/mesa/program/ir_to_mesa.cpp b/src/mesa/program/ir_to_mesa.cpp index d06b83261c..2fd0507c2f 100644 --- a/src/mesa/program/ir_to_mesa.cpp +++ b/src/mesa/program/ir_to_mesa.cpp @@ -2240,6 +2240,7 @@ _mesa_glsl_compile_shader(GLcontext *ctx, struct gl_shader *shader) progress = do_dead_code_unlinked(state, shader->ir) || progress; progress = do_constant_variable_unlinked(shader->ir) || progress; progress = do_constant_folding(shader->ir) || progress; + progress = do_algebraic(shader->ir) || progress; progress = do_if_return(shader->ir) || progress; if (ctx->Shader.EmitNoIfs) progress = do_if_to_cond_assign(shader->ir) || progress; -- cgit v1.2.3 From 66d4c65ee2c311ea0c71c39a28456d0c11798d6b Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 27 Jul 2010 11:28:26 -0700 Subject: glsl2: Make the dead code handler make its own talloc context. This way, we don't need to pass in a parse state, and the context doesn't grow with the number of passes through optimization. --- src/glsl/ir_dead_code.cpp | 12 ++++++------ src/glsl/ir_optimization.h | 6 ++---- src/glsl/main.cpp | 2 +- src/mesa/program/ir_to_mesa.cpp | 2 +- 4 files changed, 10 insertions(+), 12 deletions(-) (limited to 'src/glsl/main.cpp') diff --git a/src/glsl/ir_dead_code.cpp b/src/glsl/ir_dead_code.cpp index ea78107f49..4804407bdc 100644 --- a/src/glsl/ir_dead_code.cpp +++ b/src/glsl/ir_dead_code.cpp @@ -146,13 +146,12 @@ ir_dead_code_visitor::visit_leave(ir_assignment *ir) * for usage on an unlinked instruction stream. */ bool -do_dead_code(struct _mesa_glsl_parse_state *state, - exec_list *instructions) +do_dead_code(exec_list *instructions) { ir_dead_code_visitor v; bool progress = false; - v.mem_ctx = state; + v.mem_ctx = talloc_new(NULL); v.run(instructions); foreach_iter(exec_list_iterator, iter, v.variable_list) { @@ -188,6 +187,8 @@ do_dead_code(struct _mesa_glsl_parse_state *state, progress = true; } } + talloc_free(v.mem_ctx); + return progress; } @@ -199,8 +200,7 @@ do_dead_code(struct _mesa_glsl_parse_state *state, * with global scope. */ bool -do_dead_code_unlinked(struct _mesa_glsl_parse_state *state, - exec_list *instructions) +do_dead_code_unlinked(exec_list *instructions) { bool progress = false; @@ -211,7 +211,7 @@ do_dead_code_unlinked(struct _mesa_glsl_parse_state *state, foreach_iter(exec_list_iterator, sigiter, *f) { ir_function_signature *sig = (ir_function_signature *) sigiter.get(); - if (do_dead_code(state, &sig->body)) + if (do_dead_code(&sig->body)) progress = true; } } diff --git a/src/glsl/ir_optimization.h b/src/glsl/ir_optimization.h index 4f39565e5f..5dbb025d35 100644 --- a/src/glsl/ir_optimization.h +++ b/src/glsl/ir_optimization.h @@ -33,11 +33,9 @@ bool do_constant_folding(exec_list *instructions); bool do_constant_variable(exec_list *instructions); bool do_constant_variable_unlinked(exec_list *instructions); bool do_copy_propagation(exec_list *instructions); -bool do_dead_code(struct _mesa_glsl_parse_state *state, - exec_list *instructions); +bool do_dead_code(exec_list *instructions); bool do_dead_code_local(exec_list *instructions); -bool do_dead_code_unlinked(struct _mesa_glsl_parse_state *state, - exec_list *instructions); +bool do_dead_code_unlinked(exec_list *instructions); bool do_div_to_mul_rcp(exec_list *instructions); bool do_function_inlining(exec_list *instructions); bool do_if_return(exec_list *instructions); diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp index b62902278c..08b133f124 100644 --- a/src/glsl/main.cpp +++ b/src/glsl/main.cpp @@ -162,7 +162,7 @@ compile_shader(struct gl_shader *shader) progress = do_if_simplification(shader->ir) || progress; progress = do_copy_propagation(shader->ir) || progress; progress = do_dead_code_local(shader->ir) || progress; - progress = do_dead_code_unlinked(state, shader->ir) || progress; + progress = do_dead_code_unlinked(shader->ir) || progress; progress = do_constant_variable_unlinked(shader->ir) || progress; progress = do_constant_folding(shader->ir) || progress; progress = do_algebraic(shader->ir) || progress; diff --git a/src/mesa/program/ir_to_mesa.cpp b/src/mesa/program/ir_to_mesa.cpp index 5cc999c2e3..409b6d7288 100644 --- a/src/mesa/program/ir_to_mesa.cpp +++ b/src/mesa/program/ir_to_mesa.cpp @@ -2237,7 +2237,7 @@ _mesa_glsl_compile_shader(GLcontext *ctx, struct gl_shader *shader) progress = do_if_simplification(shader->ir) || progress; progress = do_copy_propagation(shader->ir) || progress; progress = do_dead_code_local(shader->ir) || progress; - progress = do_dead_code_unlinked(state, shader->ir) || progress; + progress = do_dead_code_unlinked(shader->ir) || progress; progress = do_constant_variable_unlinked(shader->ir) || progress; progress = do_constant_folding(shader->ir) || progress; progress = do_algebraic(shader->ir) || progress; -- cgit v1.2.3 From 784695442c415cf0be882434a25671ecfb635d34 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 30 Jul 2010 17:04:49 -0700 Subject: glsl2: Add new tree grafting optimization pass. --- src/glsl/Makefile | 1 + src/glsl/ir_optimization.h | 1 + src/glsl/ir_tree_grafting.cpp | 356 ++++++++++++++++++++++++++++++++++++++++ src/glsl/linker.cpp | 1 + src/glsl/main.cpp | 1 + src/mesa/program/ir_to_mesa.cpp | 1 + 6 files changed, 361 insertions(+) create mode 100644 src/glsl/ir_tree_grafting.cpp (limited to 'src/glsl/main.cpp') diff --git a/src/glsl/Makefile b/src/glsl/Makefile index aa1922f3be..0254fec756 100644 --- a/src/glsl/Makefile +++ b/src/glsl/Makefile @@ -56,6 +56,7 @@ CXX_SOURCES = \ ir_print_visitor.cpp \ ir_reader.cpp \ ir_swizzle_swizzle.cpp \ + ir_tree_grafting.cpp \ ir_validate.cpp \ ir_variable.cpp \ ir_variable_refcount.cpp \ diff --git a/src/glsl/ir_optimization.h b/src/glsl/ir_optimization.h index 5dbb025d35..55ec327193 100644 --- a/src/glsl/ir_optimization.h +++ b/src/glsl/ir_optimization.h @@ -44,5 +44,6 @@ bool do_if_to_cond_assign(exec_list *instructions); bool do_mat_op_to_vec(exec_list *instructions); bool do_mod_to_fract(exec_list *instructions); bool do_swizzle_swizzle(exec_list *instructions); +bool do_tree_grafting(exec_list *instructions); bool do_vec_index_to_cond_assign(exec_list *instructions); bool do_vec_index_to_swizzle(exec_list *instructions); diff --git a/src/glsl/ir_tree_grafting.cpp b/src/glsl/ir_tree_grafting.cpp new file mode 100644 index 0000000000..6f62de758b --- /dev/null +++ b/src/glsl/ir_tree_grafting.cpp @@ -0,0 +1,356 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_tree_grafting.cpp + * + * Takes assignments to variables that are dereferenced only once and + * pastes the RHS expression into where the variable is dereferenced. + * + * In the process of various operations like function inlining and + * tertiary op handling, we'll end up with our expression trees having + * been chopped up into a series of assignments of short expressions + * to temps. Other passes like ir_algebraic.cpp would prefer to see + * the deepest expression trees they can to try to optimize them. + * + * This is a lot like copy propagaton. In comparison, copy + * propagation only acts on plain copies, not arbitrary expressions on + * the RHS. Generally, we wouldn't want to go pasting some + * complicated expression everywhere it got used, though, so we don't + * handle expressions in that pass. + * + * The hard part is making sure we don't move an expression across + * some other assignments that would change the value of the + * expression. So we split this into two passes: First, find the + * variables in our scope which are written to once and read once, and + * then go through basic blocks seeing if we find an opportunity to + * move those expressions safely. + */ + +#include "ir.h" +#include "ir_visitor.h" +#include "ir_variable_refcount.h" +#include "ir_basic_block.h" +#include "ir_optimization.h" +#include "glsl_types.h" + +static bool debug = false; + +class ir_tree_grafting_visitor : public ir_hierarchical_visitor { +public: + ir_tree_grafting_visitor(ir_assignment *graft_assign, + ir_variable *graft_var) + { + this->progress = false; + this->graft_assign = graft_assign; + this->graft_var = graft_var; + } + + virtual ir_visitor_status visit_leave(class ir_assignment *); + virtual ir_visitor_status visit_enter(class ir_call *); + virtual ir_visitor_status visit_enter(class ir_expression *); + virtual ir_visitor_status visit_enter(class ir_function *); + virtual ir_visitor_status visit_enter(class ir_function_signature *); + virtual ir_visitor_status visit_enter(class ir_if *); + virtual ir_visitor_status visit_enter(class ir_loop *); + virtual ir_visitor_status visit_enter(class ir_swizzle *); + virtual ir_visitor_status visit_enter(class ir_texture *); + + bool do_graft(ir_rvalue **rvalue); + + bool progress; + ir_variable *graft_var; + ir_assignment *graft_assign; +}; + +struct find_deref_info { + ir_variable *var; + bool found; +}; + +void +dereferences_variable_callback(ir_instruction *ir, void *data) +{ + struct find_deref_info *info = (struct find_deref_info *)data; + + if (ir == info->var) + info->found = true; +} + +static bool +dereferences_variable(ir_instruction *ir, ir_variable *var) +{ + struct find_deref_info info; + + info.var = var; + info.found = false; + + visit_tree(ir, dereferences_variable_callback, &info); + + return info.found; +} + +bool +ir_tree_grafting_visitor::do_graft(ir_rvalue **rvalue) +{ + if (!*rvalue) + return false; + + ir_dereference_variable *deref = (*rvalue)->as_dereference_variable(); + + if (!deref || deref->var != this->graft_var) + return false; + + if (debug) { + printf("GRAFTING:\n"); + this->graft_assign->rhs->print(); + printf("\n"); + printf("TO:\n"); + (*rvalue)->print(); + printf("\n"); + } + + this->graft_assign->remove(); + *rvalue = this->graft_assign->rhs; + + this->progress = true; + return true; +} + +ir_visitor_status +ir_tree_grafting_visitor::visit_enter(ir_loop *ir) +{ + (void)ir; + /* Do not traverse into the body of the loop since that is a + * different basic block. + */ + return visit_stop; +} + +ir_visitor_status +ir_tree_grafting_visitor::visit_leave(ir_assignment *ir) +{ + if (do_graft(&ir->rhs) || + do_graft(&ir->condition)) + return visit_stop; + + /* If this assignment updates a variable used in the assignment + * we're trying to graft, then we're done. + */ + if (dereferences_variable(this->graft_assign->rhs, + ir->lhs->variable_referenced())) { + if (debug) { + printf("graft killed by: "); + ir->print(); + printf("\n"); + } + return visit_stop; + } + + return visit_continue; +} + +ir_visitor_status +ir_tree_grafting_visitor::visit_enter(ir_function *ir) +{ + (void) ir; + return visit_continue_with_parent; +} + +ir_visitor_status +ir_tree_grafting_visitor::visit_enter(ir_function_signature *ir) +{ + (void)ir; + return visit_continue_with_parent; +} + +ir_visitor_status +ir_tree_grafting_visitor::visit_enter(ir_call *ir) +{ + /* Reminder: iterating ir_call iterates its parameters. */ + foreach_iter(exec_list_iterator, iter, *ir) { + ir_rvalue *ir = (ir_rvalue *)iter.get(); + ir_rvalue *new_ir = ir; + + if (do_graft(&new_ir)) { + ir->replace_with(new_ir); + return visit_stop; + } + } + + return visit_continue; +} + +ir_visitor_status +ir_tree_grafting_visitor::visit_enter(ir_expression *ir) +{ + for (unsigned int i = 0; i < ir->get_num_operands(); i++) { + if (do_graft(&ir->operands[i])) + return visit_stop; + } + + return visit_continue; +} + +ir_visitor_status +ir_tree_grafting_visitor::visit_enter(ir_if *ir) +{ + if (do_graft(&ir->condition)) + return visit_stop; + + /* Do not traverse into the body of the if-statement since that is a + * different basic block. + */ + return visit_continue_with_parent; +} + +ir_visitor_status +ir_tree_grafting_visitor::visit_enter(ir_swizzle *ir) +{ + if (do_graft(&ir->val)) + return visit_stop; + + return visit_continue; +} + +ir_visitor_status +ir_tree_grafting_visitor::visit_enter(ir_texture *ir) +{ + if (do_graft(&ir->coordinate) || + do_graft(&ir->projector) || + do_graft(&ir->shadow_comparitor)) + return visit_stop; + + switch (ir->op) { + case ir_tex: + break; + case ir_txb: + if (do_graft(&ir->lod_info.bias)) + return visit_stop; + break; + case ir_txf: + case ir_txl: + if (do_graft(&ir->lod_info.lod)) + return visit_stop; + break; + case ir_txd: + if (do_graft(&ir->lod_info.grad.dPdx) || + do_graft(&ir->lod_info.grad.dPdy)) + return visit_stop; + break; + } + + return visit_continue; +} + +struct tree_grafting_info { + ir_variable_refcount_visitor *refs; + bool progress; +}; + +static bool +try_tree_grafting(ir_assignment *start, + ir_variable *lhs_var, + ir_instruction *bb_last) +{ + ir_tree_grafting_visitor v(start, lhs_var); + + if (debug) { + printf("trying to graft: "); + lhs_var->print(); + printf("\n"); + } + + for (ir_instruction *ir = (ir_instruction *)start->next; + ir != bb_last->next; + ir = (ir_instruction *)ir->next) { + + if (debug) { + printf("- "); + ir->print(); + printf("\n"); + } + + ir_visitor_status s = ir->accept(&v); + if (s == visit_stop) + return v.progress; + } + + return false; +} + +static void +tree_grafting_basic_block(ir_instruction *bb_first, + ir_instruction *bb_last, + void *data) +{ + struct tree_grafting_info *info = (struct tree_grafting_info *)data; + ir_instruction *ir, *next; + + for (ir = bb_first, next = (ir_instruction *)ir->next; + ir != bb_last->next; + ir = next, next = (ir_instruction *)ir->next) { + ir_assignment *assign = ir->as_assignment(); + + if (!assign) + continue; + + ir_variable *lhs_var = assign->lhs->whole_variable_referenced(); + if (!lhs_var) + continue; + + struct variable_entry *entry = info->refs->get_variable_entry(lhs_var); + + if (!entry->declaration || + entry->assigned_count != 1 || + entry->referenced_count != 2) + continue; + + assert(assign == entry->assign); + + /* Found a possibly graftable assignment. Now, walk through the + * rest of the BB seeing if the deref is here, and if nothing interfered with + * pasting its expression's values in between. + */ + info->progress |= try_tree_grafting(assign, lhs_var, bb_last); + } +} + +/** + * Does a copy propagation pass on the code present in the instruction stream. + */ +bool +do_tree_grafting(exec_list *instructions) +{ + ir_variable_refcount_visitor refs; + struct tree_grafting_info info; + + info.progress = false; + info.refs = &refs; + + visit_list_elements(info.refs, instructions); + + call_for_basic_blocks(instructions, tree_grafting_basic_block, &info); + + return info.progress; +} diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp index e9daad28ec..9b47e4788f 100644 --- a/src/glsl/linker.cpp +++ b/src/glsl/linker.cpp @@ -1286,6 +1286,7 @@ link_shaders(struct gl_shader_program *prog) progress = do_copy_propagation(ir) || progress; progress = do_dead_code_local(ir) || progress; progress = do_dead_code(ir) || progress; + progress = do_tree_grafting(ir) || progress; progress = do_constant_variable_unlinked(ir) || progress; progress = do_constant_folding(ir) || progress; progress = do_if_return(ir) || progress; diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp index 08b133f124..d557dcc493 100644 --- a/src/glsl/main.cpp +++ b/src/glsl/main.cpp @@ -163,6 +163,7 @@ compile_shader(struct gl_shader *shader) progress = do_copy_propagation(shader->ir) || progress; progress = do_dead_code_local(shader->ir) || progress; progress = do_dead_code_unlinked(shader->ir) || progress; + progress = do_tree_grafting(shader->ir) || progress; progress = do_constant_variable_unlinked(shader->ir) || progress; progress = do_constant_folding(shader->ir) || progress; progress = do_algebraic(shader->ir) || progress; diff --git a/src/mesa/program/ir_to_mesa.cpp b/src/mesa/program/ir_to_mesa.cpp index e62395a3b9..9274723eb7 100644 --- a/src/mesa/program/ir_to_mesa.cpp +++ b/src/mesa/program/ir_to_mesa.cpp @@ -2485,6 +2485,7 @@ _mesa_glsl_compile_shader(GLcontext *ctx, struct gl_shader *shader) progress = do_copy_propagation(shader->ir) || progress; progress = do_dead_code_local(shader->ir) || progress; progress = do_dead_code_unlinked(shader->ir) || progress; + progress = do_tree_grafting(shader->ir) || progress; progress = do_constant_variable_unlinked(shader->ir) || progress; progress = do_constant_folding(shader->ir) || progress; progress = do_algebraic(shader->ir) || progress; -- cgit v1.2.3 From 7ffe40532f6b22d9b80caeac0fc3b9495619186a Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Mon, 2 Aug 2010 11:46:22 -0700 Subject: glsl2: Clean-up two 'unused variable' warnings --- src/glsl/ir_validate.cpp | 2 ++ src/glsl/main.cpp | 3 +++ 2 files changed, 5 insertions(+) (limited to 'src/glsl/main.cpp') diff --git a/src/glsl/ir_validate.cpp b/src/glsl/ir_validate.cpp index f9f781b36a..712e1376fa 100644 --- a/src/glsl/ir_validate.cpp +++ b/src/glsl/ir_validate.cpp @@ -336,6 +336,8 @@ ir_validate::validate_ir(ir_instruction *ir, void *data) void check_node_type(ir_instruction *ir, void *data) { + (void) data; + if (ir->ir_type <= ir_type_unset || ir->ir_type >= ir_type_max) { printf("Instruction node with unset type\n"); ir->print(); printf("\n"); diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp index d557dcc493..bc7292d155 100644 --- a/src/glsl/main.cpp +++ b/src/glsl/main.cpp @@ -45,6 +45,9 @@ struct gl_shader * _mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type) { struct gl_shader *shader; + + (void) ctx; + assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER); shader = talloc_zero(NULL, struct gl_shader); if (shader) { -- cgit v1.2.3 From 8bebbeb7c5b26ec9166a4644a2c051238d18509b Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 9 Aug 2010 17:03:46 -0700 Subject: glsl2: Add constant propagation. Whereas constant folding evaluates constant expressions at rvalue nodes, constant propagation tracks constant components of vectors across execution to replace (possibly swizzled) variable dereferences with constant values, triggering possible constant folding or reduced variable liveness. --- src/glsl/Makefile | 1 + src/glsl/ir_constant_propagation.cpp | 481 +++++++++++++++++++++++++++++++++++ src/glsl/ir_optimization.h | 1 + src/glsl/linker.cpp | 1 + src/glsl/main.cpp | 1 + src/mesa/program/ir_to_mesa.cpp | 1 + 6 files changed, 486 insertions(+) create mode 100644 src/glsl/ir_constant_propagation.cpp (limited to 'src/glsl/main.cpp') diff --git a/src/glsl/Makefile b/src/glsl/Makefile index 0f8b290b65..841e2b9ce9 100644 --- a/src/glsl/Makefile +++ b/src/glsl/Makefile @@ -34,6 +34,7 @@ CXX_SOURCES = \ ir_clone.cpp \ ir_constant_expression.cpp \ ir_constant_folding.cpp \ + ir_constant_propagation.cpp \ ir_constant_variable.cpp \ ir_copy_propagation.cpp \ ir.cpp \ diff --git a/src/glsl/ir_constant_propagation.cpp b/src/glsl/ir_constant_propagation.cpp new file mode 100644 index 0000000000..adae0aa117 --- /dev/null +++ b/src/glsl/ir_constant_propagation.cpp @@ -0,0 +1,481 @@ +/* + * Constantright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * constant of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, constant, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above constantright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR CONSTANTRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file ir_constant_propagation.cpp + * + * Tracks assignments of constants to channels of variables, and + * usage of those constant channels with direct usage of the constants. + * + * This can lead to constant folding and algebraic optimizations in + * those later expressions, while causing no increase in instruction + * count (due to constants being generally free to load from a + * constant push buffer or as instruction immediate values) and + * possibly reducing register pressure. + */ + +#include "ir.h" +#include "ir_visitor.h" +#include "ir_basic_block.h" +#include "ir_optimization.h" +#include "glsl_types.h" + +class acp_entry : public exec_node +{ +public: + acp_entry(ir_variable *var, unsigned write_mask, ir_constant *constant) + { + assert(var); + assert(constant); + this->var = var; + this->write_mask = write_mask; + this->constant = constant; + } + + ir_variable *var; + ir_constant *constant; + unsigned write_mask; +}; + + +class kill_entry : public exec_node +{ +public: + kill_entry(ir_variable *var, unsigned write_mask) + { + assert(var); + this->var = var; + this->write_mask = write_mask; + } + + ir_variable *var; + unsigned write_mask; +}; + +class ir_constant_propagation_visitor : public ir_hierarchical_visitor { +public: + ir_constant_propagation_visitor() + { + progress = false; + mem_ctx = talloc_new(0); + this->acp = new(mem_ctx) exec_list; + this->kills = new(mem_ctx) exec_list; + } + ~ir_constant_propagation_visitor() + { + talloc_free(mem_ctx); + } + + virtual ir_visitor_status visit_enter(class ir_loop *); + virtual ir_visitor_status visit_enter(class ir_function_signature *); + virtual ir_visitor_status visit_enter(class ir_function *); + virtual ir_visitor_status visit_enter(class ir_assignment *); + virtual ir_visitor_status visit_leave(class ir_assignment *); + virtual ir_visitor_status visit_enter(class ir_expression *); + virtual ir_visitor_status visit_enter(class ir_call *); + virtual ir_visitor_status visit_enter(class ir_if *); + virtual ir_visitor_status visit_enter(class ir_dereference_array *); + virtual ir_visitor_status visit_enter(class ir_texture *); + + void add_constant(ir_assignment *ir); + void kill(ir_variable *ir, unsigned write_mask); + void handle_if_block(exec_list *instructions); + void handle_rvalue(ir_rvalue **rvalue); + + /** List of acp_entry: The available constants to propagate */ + exec_list *acp; + + /** + * List of kill_entry: The masks of variables whose values were + * killed in this block. + */ + exec_list *kills; + + bool progress; + + bool killed_all; + + void *mem_ctx; +}; + + +void +ir_constant_propagation_visitor::handle_rvalue(ir_rvalue **rvalue) +{ + if (!*rvalue) + return; + + const glsl_type *type = (*rvalue)->type; + if (!type->is_scalar() && !type->is_vector()) + return; + + ir_swizzle *swiz = NULL; + ir_dereference_variable *deref = (*rvalue)->as_dereference_variable(); + if (!deref) { + swiz = (*rvalue)->as_swizzle(); + if (!swiz) + return; + + deref = swiz->val->as_dereference_variable(); + if (!deref) + return; + } + + ir_constant_data data; + memset(&data, 0, sizeof(data)); + + for (unsigned int i = 0; i < type->components(); i++) { + int channel; + acp_entry *found = NULL; + + if (swiz) { + switch (i) { + case 0: channel = swiz->mask.x; break; + case 1: channel = swiz->mask.y; break; + case 2: channel = swiz->mask.z; break; + case 3: channel = swiz->mask.w; break; + default: assert(!"shouldn't be reached"); channel = 0; break; + } + } else { + channel = i; + } + + foreach_iter(exec_list_iterator, iter, *this->acp) { + acp_entry *entry = (acp_entry *)iter.get(); + if (entry->var == deref->var && entry->write_mask & (1 << channel)) { + found = entry; + break; + } + } + + if (!found) + return; + + switch (type->base_type) { + case GLSL_TYPE_FLOAT: + data.f[i] = found->constant->value.f[channel]; + break; + case GLSL_TYPE_INT: + data.i[i] = found->constant->value.i[channel]; + break; + case GLSL_TYPE_UINT: + data.u[i] = found->constant->value.u[channel]; + break; + case GLSL_TYPE_BOOL: + data.b[i] = found->constant->value.b[channel]; + break; + default: + assert(!"not reached"); + break; + } + } + + *rvalue = new(talloc_parent(deref)) ir_constant(type, &data); + this->progress = true; +} + +ir_visitor_status +ir_constant_propagation_visitor::visit_enter(ir_function_signature *ir) +{ + /* Treat entry into a function signature as a completely separate + * block. Any instructions at global scope will be shuffled into + * main() at link time, so they're irrelevant to us. + */ + exec_list *orig_acp = this->acp; + exec_list *orig_kills = this->kills; + bool orig_killed_all = this->killed_all; + + this->acp = new(mem_ctx) exec_list; + this->kills = new(mem_ctx) exec_list; + this->killed_all = false; + + visit_list_elements(this, &ir->body); + + this->kills = orig_kills; + this->acp = orig_acp; + this->killed_all = orig_killed_all; + + return visit_continue_with_parent; +} + +ir_visitor_status +ir_constant_propagation_visitor::visit_enter(ir_assignment *ir) +{ + handle_rvalue(&ir->condition); + handle_rvalue(&ir->rhs); + + return visit_continue; +} + +ir_visitor_status +ir_constant_propagation_visitor::visit_leave(ir_assignment *ir) +{ + kill(ir->lhs->variable_referenced(), ir->write_mask); + + add_constant(ir); + + return visit_continue; +} + +ir_visitor_status +ir_constant_propagation_visitor::visit_enter(ir_expression *ir) +{ + for (unsigned int i = 0; i < ir->get_num_operands(); i++) { + handle_rvalue(&ir->operands[i]); + } + + return visit_continue; +} + +ir_visitor_status +ir_constant_propagation_visitor::visit_enter(ir_function *ir) +{ + (void) ir; + return visit_continue; +} + +ir_visitor_status +ir_constant_propagation_visitor::visit_enter(ir_call *ir) +{ + /* Do constant propagation on call parameters, but skip any out params */ + exec_list_iterator sig_param_iter = ir->get_callee()->parameters.iterator(); + foreach_iter(exec_list_iterator, iter, ir->actual_parameters) { + ir_variable *sig_param = (ir_variable *)sig_param_iter.get(); + ir_rvalue *param = (ir_rvalue *)iter.get(); + if (sig_param->mode != ir_var_out && sig_param->mode != ir_var_inout) { + ir_rvalue *new_param = param; + handle_rvalue(&new_param); + if (new_param != param) + param->replace_with(new_param); + else + param->accept(this); + } + sig_param_iter.next(); + } + + /* Since we're unlinked, we don't (necssarily) know the side effects of + * this call. So kill all copies. + */ + acp->make_empty(); + this->killed_all = true; + + return visit_continue_with_parent; +} + +void +ir_constant_propagation_visitor::handle_if_block(exec_list *instructions) +{ + exec_list *orig_acp = this->acp; + exec_list *orig_kills = this->kills; + bool orig_killed_all = this->killed_all; + + this->acp = new(mem_ctx) exec_list; + this->kills = new(mem_ctx) exec_list; + this->killed_all = false; + + /* Populate the initial acp with a constant of the original */ + foreach_iter(exec_list_iterator, iter, *orig_acp) { + acp_entry *a = (acp_entry *)iter.get(); + this->acp->push_tail(new(this->mem_ctx) acp_entry(a->var, a->write_mask, + a->constant)); + } + + visit_list_elements(this, instructions); + + if (this->killed_all) { + orig_acp->make_empty(); + } + + exec_list *new_kills = this->kills; + this->kills = orig_kills; + this->acp = orig_acp; + this->killed_all = this->killed_all || orig_killed_all; + + foreach_iter(exec_list_iterator, iter, *new_kills) { + kill_entry *k = (kill_entry *)iter.get(); + kill(k->var, k->write_mask); + } +} + +ir_visitor_status +ir_constant_propagation_visitor::visit_enter(ir_if *ir) +{ + ir->condition->accept(this); + handle_rvalue(&ir->condition); + + handle_if_block(&ir->then_instructions); + handle_if_block(&ir->else_instructions); + + /* handle_if_block() already descended into the children. */ + return visit_continue_with_parent; +} + +ir_visitor_status +ir_constant_propagation_visitor::visit_enter(ir_dereference_array *ir) +{ + handle_rvalue(&ir->array_index); + return visit_continue; +} + +ir_visitor_status +ir_constant_propagation_visitor::visit_enter(ir_texture *ir) +{ + handle_rvalue(&ir->coordinate); + handle_rvalue(&ir->projector); + handle_rvalue(&ir->shadow_comparitor); + + switch (ir->op) { + case ir_tex: + break; + case ir_txb: + handle_rvalue(&ir->lod_info.bias); + break; + case ir_txf: + case ir_txl: + handle_rvalue(&ir->lod_info.lod); + break; + case ir_txd: + handle_rvalue(&ir->lod_info.grad.dPdx); + handle_rvalue(&ir->lod_info.grad.dPdy); + break; + } + + return visit_continue; +} + +ir_visitor_status +ir_constant_propagation_visitor::visit_enter(ir_loop *ir) +{ + exec_list *orig_acp = this->acp; + exec_list *orig_kills = this->kills; + bool orig_killed_all = this->killed_all; + + /* FINISHME: For now, the initial acp for loops is totally empty. + * We could go through once, then go through again with the acp + * cloned minus the killed entries after the first run through. + */ + this->acp = new(mem_ctx) exec_list; + this->kills = new(mem_ctx) exec_list; + this->killed_all = false; + + visit_list_elements(this, &ir->body_instructions); + + if (this->killed_all) { + orig_acp->make_empty(); + } + + exec_list *new_kills = this->kills; + this->kills = orig_kills; + this->acp = orig_acp; + this->killed_all = this->killed_all || orig_killed_all; + + foreach_iter(exec_list_iterator, iter, *new_kills) { + kill_entry *k = (kill_entry *)iter.get(); + kill(k->var, k->write_mask); + } + + /* already descended into the children. */ + return visit_continue_with_parent; +} + +void +ir_constant_propagation_visitor::kill(ir_variable *var, unsigned write_mask) +{ + assert(var != NULL); + + /* We don't track non-vectors. */ + if (!var->type->is_vector() && !var->type->is_scalar()) + return; + + /* Remove any entries currently in the ACP for this kill. */ + foreach_iter(exec_list_iterator, iter, *this->acp) { + acp_entry *entry = (acp_entry *)iter.get(); + + if (entry->var == var) { + entry->write_mask &= ~write_mask; + if (entry->write_mask == 0) + entry->remove(); + } + } + + /* Add this writemask of the variable to the list of killed + * variables in this block. + */ + foreach_iter(exec_list_iterator, iter, *this->kills) { + kill_entry *entry = (kill_entry *)iter.get(); + + if (entry->var == var) { + entry->write_mask |= write_mask; + return; + } + } + /* Not already in the list. Make new entry. */ + this->kills->push_tail(new(this->mem_ctx) kill_entry(var, write_mask)); +} + +/** + * Adds an entry to the available constant list if it's a plain assignment + * of a variable to a variable. + */ +void +ir_constant_propagation_visitor::add_constant(ir_assignment *ir) +{ + acp_entry *entry; + + if (ir->condition) { + ir_constant *condition = ir->condition->as_constant(); + if (!condition || !condition->value.b[0]) + return; + } + + if (!ir->write_mask) + return; + + ir_dereference_variable *deref = ir->lhs->as_dereference_variable(); + ir_constant *constant = ir->rhs->as_constant(); + + if (!deref || !constant) + return; + + /* Only do constant propagation on vectors. Constant matrices, + * arrays, or structures would require more work elsewhere. + */ + if (!deref->var->type->is_vector() && !deref->var->type->is_scalar()) + return; + + entry = new(this->mem_ctx) acp_entry(deref->var, ir->write_mask, constant); + this->acp->push_tail(entry); +} + +/** + * Does a constant propagation pass on the code present in the instruction stream. + */ +bool +do_constant_propagation(exec_list *instructions) +{ + ir_constant_propagation_visitor v; + + visit_list_elements(&v, instructions); + + return v.progress; +} diff --git a/src/glsl/ir_optimization.h b/src/glsl/ir_optimization.h index c6e7beb447..97a0c25216 100644 --- a/src/glsl/ir_optimization.h +++ b/src/glsl/ir_optimization.h @@ -33,6 +33,7 @@ bool do_constant_folding(exec_list *instructions); bool do_constant_variable(exec_list *instructions); bool do_constant_variable_unlinked(exec_list *instructions); bool do_copy_propagation(exec_list *instructions); +bool do_constant_propagation(exec_list *instructions); bool do_dead_code(exec_list *instructions); bool do_dead_code_local(exec_list *instructions); bool do_dead_code_unlinked(exec_list *instructions); diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp index e93c2f5554..52c9322788 100644 --- a/src/glsl/linker.cpp +++ b/src/glsl/linker.cpp @@ -1296,6 +1296,7 @@ link_shaders(struct gl_shader_program *prog) progress = do_dead_code_local(ir) || progress; progress = do_dead_code(ir) || progress; progress = do_tree_grafting(ir) || progress; + progress = do_constant_propagation(ir) || progress; progress = do_constant_variable(ir) || progress; progress = do_constant_folding(ir) || progress; progress = do_algebraic(ir) || progress; diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp index bc7292d155..24d6076d07 100644 --- a/src/glsl/main.cpp +++ b/src/glsl/main.cpp @@ -167,6 +167,7 @@ compile_shader(struct gl_shader *shader) progress = do_dead_code_local(shader->ir) || progress; progress = do_dead_code_unlinked(shader->ir) || progress; progress = do_tree_grafting(shader->ir) || progress; + progress = do_constant_propagation(shader->ir) || progress; progress = do_constant_variable_unlinked(shader->ir) || progress; progress = do_constant_folding(shader->ir) || progress; progress = do_algebraic(shader->ir) || progress; diff --git a/src/mesa/program/ir_to_mesa.cpp b/src/mesa/program/ir_to_mesa.cpp index c6856eb5a4..5a272ab88a 100644 --- a/src/mesa/program/ir_to_mesa.cpp +++ b/src/mesa/program/ir_to_mesa.cpp @@ -2581,6 +2581,7 @@ _mesa_glsl_compile_shader(GLcontext *ctx, struct gl_shader *shader) progress = do_dead_code_local(shader->ir) || progress; progress = do_dead_code_unlinked(shader->ir) || progress; progress = do_tree_grafting(shader->ir) || progress; + progress = do_constant_propagation(shader->ir) || progress; progress = do_constant_variable_unlinked(shader->ir) || progress; progress = do_constant_folding(shader->ir) || progress; progress = do_algebraic(shader->ir) || progress; -- cgit v1.2.3 From 5d0f430e8ed01db29d11d22e4b6c3760d8c39f8f Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 18 Aug 2010 12:02:35 -0700 Subject: mesa: Free old linked shaders when relinking new shaders. --- src/glsl/linker.cpp | 15 ++++++++++----- src/glsl/main.cpp | 6 +++++- src/glsl/program.h | 2 +- src/mesa/program/ir_to_mesa.cpp | 2 +- 4 files changed, 17 insertions(+), 8 deletions(-) (limited to 'src/glsl/main.cpp') diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp index 4172e41910..b256574446 100644 --- a/src/glsl/linker.cpp +++ b/src/glsl/linker.cpp @@ -674,7 +674,8 @@ get_main_function_signature(gl_shader *sh) * shader is returned. */ static struct gl_shader * -link_intrastage_shaders(struct gl_shader_program *prog, +link_intrastage_shaders(GLcontext *ctx, + struct gl_shader_program *prog, struct gl_shader **shader_list, unsigned num_shaders) { @@ -747,7 +748,7 @@ link_intrastage_shaders(struct gl_shader_program *prog, return NULL; } - gl_shader *const linked = _mesa_new_shader(NULL, 0, main->Type); + gl_shader *const linked = ctx->Driver.NewShader(NULL, 0, main->Type); linked->ir = new(linked) exec_list; clone_ir_list(linked, linked->ir, main->ir); @@ -1212,7 +1213,7 @@ assign_varying_locations(struct gl_shader_program *prog, void -link_shaders(struct gl_shader_program *prog) +link_shaders(GLcontext *ctx, struct gl_shader_program *prog) { prog->LinkStatus = false; prog->Validated = false; @@ -1270,12 +1271,16 @@ link_shaders(struct gl_shader_program *prog) prog->Version = max_version; + for (unsigned int i = 0; i < prog->_NumLinkedShaders; i++) { + ctx->Driver.DeleteShader(ctx, prog->_LinkedShaders[i]); + } + /* Link all shaders for a particular stage and validate the result. */ prog->_NumLinkedShaders = 0; if (num_vert_shaders > 0) { gl_shader *const sh = - link_intrastage_shaders(prog, vert_shader_list, num_vert_shaders); + link_intrastage_shaders(ctx, prog, vert_shader_list, num_vert_shaders); if (sh == NULL) goto done; @@ -1289,7 +1294,7 @@ link_shaders(struct gl_shader_program *prog) if (num_frag_shaders > 0) { gl_shader *const sh = - link_intrastage_shaders(prog, frag_shader_list, num_frag_shaders); + link_intrastage_shaders(ctx, prog, frag_shader_list, num_frag_shaders); if (sh == NULL) goto done; diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp index 24d6076d07..cb9f8a5277 100644 --- a/src/glsl/main.cpp +++ b/src/glsl/main.cpp @@ -209,6 +209,10 @@ int main(int argc, char **argv) { int status = EXIT_SUCCESS; + GLcontext local_ctx; + GLcontext *ctx = &local_ctx; + + ctx->Driver.NewShader = _mesa_new_shader; int c; int idx = 0; @@ -265,7 +269,7 @@ main(int argc, char **argv) } if ((status == EXIT_SUCCESS) && do_link) { - link_shaders(whole_program); + link_shaders(ctx, whole_program); status = (whole_program->LinkStatus) ? EXIT_SUCCESS : EXIT_FAILURE; if (strlen(whole_program->InfoLog) > 0) diff --git a/src/glsl/program.h b/src/glsl/program.h index 0a49203d4b..ea2c4ab0dd 100644 --- a/src/glsl/program.h +++ b/src/glsl/program.h @@ -30,4 +30,4 @@ extern "C" { } extern void -link_shaders(struct gl_shader_program *prog); +link_shaders(GLcontext *ctx, struct gl_shader_program *prog); diff --git a/src/mesa/program/ir_to_mesa.cpp b/src/mesa/program/ir_to_mesa.cpp index 4f4994392d..394370d46d 100644 --- a/src/mesa/program/ir_to_mesa.cpp +++ b/src/mesa/program/ir_to_mesa.cpp @@ -2740,7 +2740,7 @@ _mesa_glsl_link_shader(GLcontext *ctx, struct gl_shader_program *prog) _mesa_reference_fragprog(ctx, &prog->FragmentProgram, NULL); if (prog->LinkStatus) { - link_shaders(prog); + link_shaders(ctx, prog); /* We don't use the linker's uniforms list, and cook up our own at * generate time. -- cgit v1.2.3