glsl: Define GL_ES preprocessor macro if API is OpenGL ES 2.0.
[profile/ivi/mesa.git] / src / glsl / main.cpp
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 #include "loop_analysis.h"
39
40 extern "C" struct gl_shader *
41 _mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type);
42
43 /* Copied from shader_api.c for the stand-alone compiler.
44  */
45 struct gl_shader *
46 _mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type)
47 {
48    struct gl_shader *shader;
49
50    (void) ctx;
51
52    assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER);
53    shader = talloc_zero(NULL, struct gl_shader);
54    if (shader) {
55       shader->Type = type;
56       shader->Name = name;
57       shader->RefCount = 1;
58    }
59    return shader;
60 }
61
62 /* Returned string will have 'ctx' as its talloc owner. */
63 static char *
64 load_text_file(void *ctx, const char *file_name)
65 {
66         char *text = NULL;
67         struct stat st;
68         ssize_t total_read = 0;
69         int fd = open(file_name, O_RDONLY);
70
71         if (fd < 0) {
72                 return NULL;
73         }
74
75         if (fstat(fd, & st) == 0) {
76            text = (char *) talloc_size(ctx, st.st_size + 1);
77                 if (text != NULL) {
78                         do {
79                                 ssize_t bytes = read(fd, text + total_read,
80                                                      st.st_size - total_read);
81                                 if (bytes < 0) {
82                                         free(text);
83                                         text = NULL;
84                                         break;
85                                 }
86
87                                 if (bytes == 0) {
88                                         break;
89                                 }
90
91                                 total_read += bytes;
92                         } while (total_read < st.st_size);
93
94                         text[total_read] = '\0';
95                 }
96         }
97
98         close(fd);
99
100         return text;
101 }
102
103
104 void
105 usage_fail(const char *name)
106 {
107       printf("%s <filename.frag|filename.vert>\n", name);
108       exit(EXIT_FAILURE);
109 }
110
111
112 int dump_ast = 0;
113 int dump_hir = 0;
114 int dump_lir = 0;
115 int do_link = 0;
116
117 const struct option compiler_opts[] = {
118    { "dump-ast", 0, &dump_ast, 1 },
119    { "dump-hir", 0, &dump_hir, 1 },
120    { "dump-lir", 0, &dump_lir, 1 },
121    { "link",     0, &do_link,  1 },
122    { NULL, 0, NULL, 0 }
123 };
124
125 void
126 compile_shader(struct gl_shader *shader)
127 {
128    struct _mesa_glsl_parse_state *state =
129       new(shader) _mesa_glsl_parse_state(NULL, shader->Type, shader);
130
131    const char *source = shader->Source;
132    state->error = preprocess(state, &source, &state->info_log,
133                              state->extensions, API_OPENGL);
134
135    if (!state->error) {
136       _mesa_glsl_lexer_ctor(state, source);
137       _mesa_glsl_parse(state);
138       _mesa_glsl_lexer_dtor(state);
139    }
140
141    if (dump_ast) {
142       foreach_list_const(n, &state->translation_unit) {
143          ast_node *ast = exec_node_data(ast_node, n, link);
144          ast->print();
145       }
146       printf("\n\n");
147    }
148
149    shader->ir = new(shader) exec_list;
150    if (!state->error && !state->translation_unit.is_empty())
151       _mesa_ast_to_hir(shader->ir, state);
152
153    /* Print out the unoptimized IR. */
154    if (!state->error && dump_hir) {
155       validate_ir_tree(shader->ir);
156       _mesa_print_ir(shader->ir, state);
157    }
158
159    /* Optimization passes */
160    if (!state->error && !shader->ir->is_empty()) {
161       bool progress;
162       do {
163          progress = false;
164
165          progress = do_function_inlining(shader->ir) || progress;
166          progress = do_if_simplification(shader->ir) || progress;
167          progress = do_copy_propagation(shader->ir) || progress;
168          progress = do_dead_code_local(shader->ir) || progress;
169          progress = do_dead_code_unlinked(shader->ir) || progress;
170          progress = do_tree_grafting(shader->ir) || progress;
171          progress = do_constant_propagation(shader->ir) || progress;
172          progress = do_constant_variable_unlinked(shader->ir) || progress;
173          progress = do_constant_folding(shader->ir) || progress;
174          progress = do_algebraic(shader->ir) || progress;
175          progress = do_vec_index_to_swizzle(shader->ir) || progress;
176          progress = do_vec_index_to_cond_assign(shader->ir) || progress;
177          progress = do_swizzle_swizzle(shader->ir) || progress;
178
179          loop_state *ls = analyze_loop_variables(shader->ir);
180          progress = set_loop_controls(shader->ir, ls) || progress;
181          progress = unroll_loops(shader->ir, ls) || progress;
182          delete ls;
183       } while (progress);
184
185       validate_ir_tree(shader->ir);
186    }
187
188
189    /* Print out the resulting IR */
190    if (!state->error && dump_lir) {
191       _mesa_print_ir(shader->ir, state);
192    }
193
194    shader->symbols = state->symbols;
195    shader->CompileStatus = !state->error;
196    shader->Version = state->language_version;
197    memcpy(shader->builtins_to_link, state->builtins_to_link,
198           sizeof(shader->builtins_to_link[0]) * state->num_builtins_to_link);
199    shader->num_builtins_to_link = state->num_builtins_to_link;
200
201    if (shader->InfoLog)
202       talloc_free(shader->InfoLog);
203
204    shader->InfoLog = state->info_log;
205
206    /* Retain any live IR, but trash the rest. */
207    reparent_ir(shader->ir, shader);
208
209    talloc_free(state);
210
211    return;
212 }
213
214 int
215 main(int argc, char **argv)
216 {
217    int status = EXIT_SUCCESS;
218    GLcontext local_ctx;
219    GLcontext *ctx = &local_ctx;
220
221    ctx->Driver.NewShader = _mesa_new_shader;
222
223    int c;
224    int idx = 0;
225    while ((c = getopt_long(argc, argv, "", compiler_opts, &idx)) != -1)
226       /* empty */ ;
227
228
229    if (argc <= optind)
230       usage_fail(argv[0]);
231
232    struct gl_shader_program *whole_program;
233
234    whole_program = talloc_zero (NULL, struct gl_shader_program);
235    assert(whole_program != NULL);
236
237    for (/* empty */; argc > optind; optind++) {
238       whole_program->Shaders = (struct gl_shader **)
239          talloc_realloc(whole_program, whole_program->Shaders,
240                         struct gl_shader *, whole_program->NumShaders + 1);
241       assert(whole_program->Shaders != NULL);
242
243       struct gl_shader *shader = talloc_zero(whole_program, gl_shader);
244
245       whole_program->Shaders[whole_program->NumShaders] = shader;
246       whole_program->NumShaders++;
247
248       const unsigned len = strlen(argv[optind]);
249       if (len < 6)
250          usage_fail(argv[0]);
251
252       const char *const ext = & argv[optind][len - 5];
253       if (strncmp(".vert", ext, 5) == 0)
254          shader->Type = GL_VERTEX_SHADER;
255       else if (strncmp(".geom", ext, 5) == 0)
256          shader->Type = GL_GEOMETRY_SHADER;
257       else if (strncmp(".frag", ext, 5) == 0)
258          shader->Type = GL_FRAGMENT_SHADER;
259       else
260          usage_fail(argv[0]);
261
262       shader->Source = load_text_file(whole_program, argv[optind]);
263       if (shader->Source == NULL) {
264          printf("File \"%s\" does not exist.\n", argv[optind]);
265          exit(EXIT_FAILURE);
266       }
267
268       compile_shader(shader);
269
270       if (!shader->CompileStatus) {
271          printf("Info log for %s:\n%s\n", argv[optind], shader->InfoLog);
272          status = EXIT_FAILURE;
273          break;
274       }
275    }
276
277    if ((status == EXIT_SUCCESS) && do_link)  {
278       link_shaders(ctx, whole_program);
279       status = (whole_program->LinkStatus) ? EXIT_SUCCESS : EXIT_FAILURE;
280
281       if (strlen(whole_program->InfoLog) > 0)
282          printf("Info log for linking:\n%s\n", whole_program->InfoLog);
283    }
284
285    for (unsigned i = 0; i < whole_program->_NumLinkedShaders; i++)
286       talloc_free(whole_program->_LinkedShaders[i]);
287
288    talloc_free(whole_program);
289    _mesa_glsl_release_types();
290    _mesa_glsl_release_functions();
291
292    return status;
293 }