/* * 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_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 } }; 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); /* 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; 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; } 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); _mesa_glsl_release_types(); return status; }