blob: 9301d5113f5021a296585665cc53ca33afaf324f [file] [log] [blame]
Ian Romanick61d4aa02010-06-14 14:46:09 -07001/*
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>
Ian Romanick7babbdb2010-06-15 12:47:07 -070025#include <getopt.h>
Ian Romanick61d4aa02010-06-14 14:46:09 -070026
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"
Ian Romanick8ce55db2010-06-17 12:01:18 -070037#include "program.h"
Ian Romanick61d4aa02010-06-14 14:46:09 -070038
39
40static char *
41load_text_file(const char *file_name, size_t *size)
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 *size = 0;
49 if (fd < 0) {
50 return NULL;
51 }
52
53 if (fstat(fd, & st) == 0) {
54 text = (char *) malloc(st.st_size + 1);
55 if (text != NULL) {
56 do {
57 ssize_t bytes = read(fd, text + total_read,
58 st.st_size - total_read);
59 if (bytes < 0) {
60 free(text);
61 text = NULL;
62 break;
63 }
64
65 if (bytes == 0) {
66 break;
67 }
68
69 total_read += bytes;
70 } while (total_read < st.st_size);
71
72 text[total_read] = '\0';
73 *size = total_read;
74 }
75 }
76
77 close(fd);
78
79 return text;
80}
81
82
Ian Romanick2b368952010-06-15 12:00:37 -070083void
84usage_fail(const char *name)
85{
86 printf("%s <filename.frag|filename.vert>\n", name);
87 exit(EXIT_FAILURE);
88}
89
90
Ian Romanick7babbdb2010-06-15 12:47:07 -070091int dump_ast = 0;
Ian Romanick81e17472010-06-15 12:51:38 -070092int dump_lir = 0;
Ian Romanickc648a122010-06-17 19:51:48 -070093int do_link = 0;
Ian Romanick7babbdb2010-06-15 12:47:07 -070094
95const struct option compiler_opts[] = {
96 { "dump-ast", 0, &dump_ast, 1 },
Ian Romanick81e17472010-06-15 12:51:38 -070097 { "dump-lir", 0, &dump_lir, 1 },
Ian Romanickc648a122010-06-17 19:51:48 -070098 { "link", 0, &do_link, 1 },
Ian Romanick7babbdb2010-06-15 12:47:07 -070099 { NULL, 0, NULL, 0 }
100};
101
Ian Romanick8ce55db2010-06-17 12:01:18 -0700102void
Kenneth Graunke29e60872010-06-17 15:28:34 -0700103compile_shader(struct glsl_shader *shader)
Ian Romanick61d4aa02010-06-14 14:46:09 -0700104{
105 struct _mesa_glsl_parse_state state;
Ian Romanick61d4aa02010-06-14 14:46:09 -0700106
Ian Romanickfc0ef642010-06-15 12:03:10 -0700107 memset(& state, 0, sizeof(state));
Kenneth Graunke29e60872010-06-17 15:28:34 -0700108 switch (shader->Type) {
Ian Romanick8ce55db2010-06-17 12:01:18 -0700109 case GL_VERTEX_SHADER: state.target = vertex_shader; break;
110 case GL_FRAGMENT_SHADER: state.target = fragment_shader; break;
111 case GL_GEOMETRY_SHADER: state.target = geometry_shader; break;
112 }
113
Ian Romanick61d4aa02010-06-14 14:46:09 -0700114 state.scanner = NULL;
115 state.translation_unit.make_empty();
116 state.symbols = new glsl_symbol_table;
117 state.error = false;
118 state.temp_index = 0;
119 state.loop_or_switch_nesting = NULL;
120 state.ARB_texture_rectangle_enable = true;
121
Kenneth Graunke29e60872010-06-17 15:28:34 -0700122 _mesa_glsl_lexer_ctor(& state, shader->Source, shader->SourceLen);
Ian Romanick54992c32010-06-14 14:47:26 -0700123 _mesa_glsl_parse(& state);
124 _mesa_glsl_lexer_dtor(& state);
Ian Romanick61d4aa02010-06-14 14:46:09 -0700125
Ian Romanick7babbdb2010-06-15 12:47:07 -0700126 if (dump_ast) {
127 foreach_list_const(n, &state.translation_unit) {
128 ast_node *ast = exec_node_data(ast_node, n, link);
129 ast->print();
130 }
131 printf("\n\n");
Ian Romanick61d4aa02010-06-14 14:46:09 -0700132 }
133
Kenneth Graunke29e60872010-06-17 15:28:34 -0700134 shader->ir.make_empty();
Ian Romanick54992c32010-06-14 14:47:26 -0700135 if (!state.error && !state.translation_unit.is_empty())
Kenneth Graunke29e60872010-06-17 15:28:34 -0700136 _mesa_ast_to_hir(&shader->ir, &state);
Ian Romanick54992c32010-06-14 14:47:26 -0700137
Ian Romanick61d4aa02010-06-14 14:46:09 -0700138 /* Optimization passes */
Kenneth Graunke29e60872010-06-17 15:28:34 -0700139 if (!state.error && !shader->ir.is_empty()) {
Ian Romanick61d4aa02010-06-14 14:46:09 -0700140 bool progress;
141 do {
142 progress = false;
143
Kenneth Graunke29e60872010-06-17 15:28:34 -0700144 progress = do_function_inlining(&shader->ir) || progress;
145 progress = do_if_simplification(&shader->ir) || progress;
146 progress = do_copy_propagation(&shader->ir) || progress;
147 progress = do_dead_code_local(&shader->ir) || progress;
148 progress = do_dead_code_unlinked(&shader->ir) || progress;
149 progress = do_constant_variable_unlinked(&shader->ir) || progress;
150 progress = do_constant_folding(&shader->ir) || progress;
151 progress = do_vec_index_to_swizzle(&shader->ir) || progress;
152 progress = do_swizzle_swizzle(&shader->ir) || progress;
Ian Romanick61d4aa02010-06-14 14:46:09 -0700153 } while (progress);
154 }
155
156 /* Print out the resulting IR */
Ian Romanick81e17472010-06-15 12:51:38 -0700157 if (!state.error && dump_lir) {
Kenneth Graunke29e60872010-06-17 15:28:34 -0700158 _mesa_print_ir(&shader->ir, &state);
Ian Romanick61d4aa02010-06-14 14:46:09 -0700159 }
160
Kenneth Graunke29e60872010-06-17 15:28:34 -0700161 shader->symbols = state.symbols;
162 shader->CompileStatus = !state.error;
Ian Romanick8ce55db2010-06-17 12:01:18 -0700163 return;
164}
Ian Romanick61d4aa02010-06-14 14:46:09 -0700165
Ian Romanick8ce55db2010-06-17 12:01:18 -0700166int
167main(int argc, char **argv)
168{
Ian Romanick6fd9fb22010-06-17 12:22:16 -0700169 int status = EXIT_SUCCESS;
Ian Romanick8ce55db2010-06-17 12:01:18 -0700170
171 int c;
172 int idx = 0;
173 while ((c = getopt_long(argc, argv, "", compiler_opts, &idx)) != -1)
174 /* empty */ ;
175
176
177 if (argc <= optind)
178 usage_fail(argv[0]);
179
Ian Romanick705fb012010-06-17 12:59:45 -0700180 struct glsl_program whole_program;
181 memset(&whole_program, 0, sizeof(whole_program));
Ian Romanick8ce55db2010-06-17 12:01:18 -0700182
Ian Romanick6fd9fb22010-06-17 12:22:16 -0700183 for (/* empty */; argc > optind; optind++) {
Ian Romanick705fb012010-06-17 12:59:45 -0700184 whole_program.Shaders = (struct glsl_shader **)
185 realloc(whole_program.Shaders,
186 sizeof(struct glsl_shader *) * (whole_program.NumShaders + 1));
187 assert(whole_program.Shaders != NULL);
Ian Romanick8ce55db2010-06-17 12:01:18 -0700188
Kenneth Graunke29e60872010-06-17 15:28:34 -0700189 struct glsl_shader *shader = new glsl_shader;
190 memset(shader, 0, sizeof(*shader));
Ian Romanick8ce55db2010-06-17 12:01:18 -0700191
Kenneth Graunke29e60872010-06-17 15:28:34 -0700192 whole_program.Shaders[whole_program.NumShaders] = shader;
Ian Romanick705fb012010-06-17 12:59:45 -0700193 whole_program.NumShaders++;
Ian Romanick8ce55db2010-06-17 12:01:18 -0700194
Ian Romanick6fd9fb22010-06-17 12:22:16 -0700195 const unsigned len = strlen(argv[optind]);
196 if (len < 6)
197 usage_fail(argv[0]);
Ian Romanick8ce55db2010-06-17 12:01:18 -0700198
Ian Romanick6fd9fb22010-06-17 12:22:16 -0700199 const char *const ext = & argv[optind][len - 5];
200 if (strncmp(".vert", ext, 5) == 0)
Kenneth Graunke29e60872010-06-17 15:28:34 -0700201 shader->Type = GL_VERTEX_SHADER;
Ian Romanick6fd9fb22010-06-17 12:22:16 -0700202 else if (strncmp(".geom", ext, 5) == 0)
Kenneth Graunke29e60872010-06-17 15:28:34 -0700203 shader->Type = GL_GEOMETRY_SHADER;
Ian Romanick6fd9fb22010-06-17 12:22:16 -0700204 else if (strncmp(".frag", ext, 5) == 0)
Kenneth Graunke29e60872010-06-17 15:28:34 -0700205 shader->Type = GL_FRAGMENT_SHADER;
Ian Romanick6fd9fb22010-06-17 12:22:16 -0700206 else
207 usage_fail(argv[0]);
208
Kenneth Graunke29e60872010-06-17 15:28:34 -0700209 shader->Source = load_text_file(argv[optind], &shader->SourceLen);
Ian Romanick6fd9fb22010-06-17 12:22:16 -0700210
Kenneth Graunke29e60872010-06-17 15:28:34 -0700211 compile_shader(shader);
Ian Romanick6fd9fb22010-06-17 12:22:16 -0700212
Kenneth Graunke29e60872010-06-17 15:28:34 -0700213 if (!shader->CompileStatus) {
Ian Romanick6fd9fb22010-06-17 12:22:16 -0700214 status = EXIT_FAILURE;
215 break;
216 }
217 }
218
Ian Romanickc648a122010-06-17 19:51:48 -0700219 if ((status == EXIT_SUCCESS) && do_link) {
Ian Romanick832dfa52010-06-17 15:04:20 -0700220 link_shaders(&whole_program);
221 status = (whole_program.LinkStatus) ? EXIT_SUCCESS : EXIT_FAILURE;
222 }
223
Ian Romanick6fd9fb22010-06-17 12:22:16 -0700224 return status;
Ian Romanick61d4aa02010-06-14 14:46:09 -0700225}