main.cpp revision 116f1d4f95d8eb0a82b272016590549632c865b3
1/* 2 * Copyright © 2008, 2009 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23#include <cstdlib> 24#include <cstdio> 25#include <getopt.h> 26 27#include <sys/types.h> 28#include <sys/stat.h> 29#include <fcntl.h> 30#include <unistd.h> 31 32#include "ast.h" 33#include "glsl_parser_extras.h" 34#include "glsl_parser.h" 35#include "ir_optimization.h" 36#include "ir_print_visitor.h" 37#include "program.h" 38 39/* Returned string will have 'ctx' as its talloc owner. */ 40static char * 41load_text_file(void *ctx, const char *file_name) 42{ 43 char *text = NULL; 44 struct stat st; 45 ssize_t total_read = 0; 46 int fd = open(file_name, O_RDONLY); 47 48 if (fd < 0) { 49 return NULL; 50 } 51 52 if (fstat(fd, & st) == 0) { 53 text = (char *) talloc_size(ctx, st.st_size + 1); 54 if (text != NULL) { 55 do { 56 ssize_t bytes = read(fd, text + total_read, 57 st.st_size - total_read); 58 if (bytes < 0) { 59 free(text); 60 text = NULL; 61 break; 62 } 63 64 if (bytes == 0) { 65 break; 66 } 67 68 total_read += bytes; 69 } while (total_read < st.st_size); 70 71 text[total_read] = '\0'; 72 } 73 } 74 75 close(fd); 76 77 return text; 78} 79 80 81void 82usage_fail(const char *name) 83{ 84 printf("%s <filename.frag|filename.vert>\n", name); 85 exit(EXIT_FAILURE); 86} 87 88 89int dump_ast = 0; 90int dump_hir = 0; 91int dump_lir = 0; 92int do_link = 0; 93 94const struct option compiler_opts[] = { 95 { "dump-ast", 0, &dump_ast, 1 }, 96 { "dump-hir", 0, &dump_hir, 1 }, 97 { "dump-lir", 0, &dump_lir, 1 }, 98 { "link", 0, &do_link, 1 }, 99 { NULL, 0, NULL, 0 } 100}; 101 102static void 103steal_memory(ir_instruction *ir, void *new_ctx) 104{ 105 talloc_steal(new_ctx, ir); 106} 107 108void 109compile_shader(struct gl_shader *shader) 110{ 111 struct _mesa_glsl_parse_state *state; 112 113 state = talloc_zero(talloc_parent(shader), struct _mesa_glsl_parse_state); 114 115 switch (shader->Type) { 116 case GL_VERTEX_SHADER: state->target = vertex_shader; break; 117 case GL_FRAGMENT_SHADER: state->target = fragment_shader; break; 118 case GL_GEOMETRY_SHADER: state->target = geometry_shader; break; 119 } 120 121 state->scanner = NULL; 122 state->translation_unit.make_empty(); 123 state->symbols = new(shader) glsl_symbol_table; 124 state->info_log = talloc_strdup(shader, ""); 125 state->error = false; 126 state->temp_index = 0; 127 state->loop_or_switch_nesting = NULL; 128 state->ARB_texture_rectangle_enable = true; 129 130 state->Const.MaxDrawBuffers = 2; 131 132 /* Create a new context for the preprocessor output. Ultimately, this 133 * should probably be the parser context, but there isn't one yet. 134 */ 135 const char *source = shader->Source; 136 state->error = preprocess(shader, &source, &state->info_log); 137 138 if (!state->error) { 139 _mesa_glsl_lexer_ctor(state, source); 140 _mesa_glsl_parse(state); 141 _mesa_glsl_lexer_dtor(state); 142 } 143 144 if (dump_ast) { 145 foreach_list_const(n, &state->translation_unit) { 146 ast_node *ast = exec_node_data(ast_node, n, link); 147 ast->print(); 148 } 149 printf("\n\n"); 150 } 151 152 shader->ir = new(shader) exec_list; 153 if (!state->error && !state->translation_unit.is_empty()) 154 _mesa_ast_to_hir(shader->ir, state); 155 156 validate_ir_tree(shader->ir); 157 158 /* Print out the unoptimized IR. */ 159 if (!state->error && dump_hir) { 160 _mesa_print_ir(shader->ir, state); 161 } 162 163 /* Optimization passes */ 164 if (!state->error && !shader->ir->is_empty()) { 165 bool progress; 166 do { 167 progress = false; 168 169 progress = do_function_inlining(shader->ir) || progress; 170 progress = do_if_simplification(shader->ir) || progress; 171 progress = do_copy_propagation(shader->ir) || progress; 172 progress = do_dead_code_local(shader->ir) || progress; 173 progress = do_dead_code_unlinked(state, shader->ir) || progress; 174 progress = do_constant_variable_unlinked(shader->ir) || progress; 175 progress = do_constant_folding(shader->ir) || progress; 176 progress = do_vec_index_to_swizzle(shader->ir) || progress; 177 progress = do_swizzle_swizzle(shader->ir) || progress; 178 } while (progress); 179 } 180 181 validate_ir_tree(shader->ir); 182 183 /* Print out the resulting IR */ 184 if (!state->error && dump_lir) { 185 _mesa_print_ir(shader->ir, state); 186 } 187 188 shader->symbols = state->symbols; 189 shader->CompileStatus = !state->error; 190 191 if (shader->InfoLog) 192 talloc_free(shader->InfoLog); 193 194 shader->InfoLog = state->info_log; 195 196 /* Retain any live IR, but trash the rest. */ 197 foreach_list(node, shader->ir) { 198 visit_tree((ir_instruction *) node, steal_memory, shader); 199 } 200 201 talloc_free(state); 202 203 return; 204} 205 206int 207main(int argc, char **argv) 208{ 209 int status = EXIT_SUCCESS; 210 211 int c; 212 int idx = 0; 213 while ((c = getopt_long(argc, argv, "", compiler_opts, &idx)) != -1) 214 /* empty */ ; 215 216 217 if (argc <= optind) 218 usage_fail(argv[0]); 219 220 struct gl_shader_program *whole_program; 221 222 whole_program = talloc_zero (NULL, struct gl_shader_program); 223 assert(whole_program != NULL); 224 225 for (/* empty */; argc > optind; optind++) { 226 whole_program->Shaders = (struct gl_shader **) 227 talloc_realloc(whole_program, whole_program->Shaders, 228 struct gl_shader *, whole_program->NumShaders + 1); 229 assert(whole_program->Shaders != NULL); 230 231 struct gl_shader *shader = talloc_zero(whole_program, gl_shader); 232 233 whole_program->Shaders[whole_program->NumShaders] = shader; 234 whole_program->NumShaders++; 235 236 const unsigned len = strlen(argv[optind]); 237 if (len < 6) 238 usage_fail(argv[0]); 239 240 const char *const ext = & argv[optind][len - 5]; 241 if (strncmp(".vert", ext, 5) == 0) 242 shader->Type = GL_VERTEX_SHADER; 243 else if (strncmp(".geom", ext, 5) == 0) 244 shader->Type = GL_GEOMETRY_SHADER; 245 else if (strncmp(".frag", ext, 5) == 0) 246 shader->Type = GL_FRAGMENT_SHADER; 247 else 248 usage_fail(argv[0]); 249 250 shader->Source = load_text_file(whole_program, argv[optind]); 251 if (shader->Source == NULL) { 252 printf("File \"%s\" does not exist.\n", argv[optind]); 253 exit(EXIT_FAILURE); 254 } 255 256 compile_shader(shader); 257 258 if (!shader->CompileStatus) { 259 printf("Info log for %s:\n%s\n", argv[optind], shader->InfoLog); 260 status = EXIT_FAILURE; 261 break; 262 } 263 } 264 265 if ((status == EXIT_SUCCESS) && do_link) { 266 link_shaders(whole_program); 267 status = (whole_program->LinkStatus) ? EXIT_SUCCESS : EXIT_FAILURE; 268 } 269 270 talloc_free(whole_program); 271 _mesa_glsl_release_types(); 272 273 return status; 274} 275