• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "src/mesa/main/shaderobj.h"
40 
41 static void
initialize_context(struct gl_context * ctx,gl_api api)42 initialize_context(struct gl_context *ctx, gl_api api)
43 {
44    memset(ctx, 0, sizeof(*ctx));
45 
46    ctx->API = api;
47 
48    ctx->Extensions.ARB_draw_buffers = GL_TRUE;
49    ctx->Extensions.ARB_fragment_coord_conventions = GL_TRUE;
50    ctx->Extensions.EXT_texture_array = GL_TRUE;
51    ctx->Extensions.NV_texture_rectangle = GL_TRUE;
52 
53    /* 1.10 minimums. */
54    ctx->Const.MaxLights = 8;
55    ctx->Const.MaxClipPlanes = 8;
56    ctx->Const.MaxTextureUnits = 2;
57 
58    /* More than the 1.10 minimum to appease parser tests taken from
59     * apps that (hopefully) already checked the number of coords.
60     */
61    ctx->Const.MaxTextureCoordUnits = 4;
62 
63    ctx->Const.VertexProgram.MaxAttribs = 16;
64    ctx->Const.VertexProgram.MaxUniformComponents = 512;
65    ctx->Const.MaxVarying = 8;
66    ctx->Const.MaxVertexTextureImageUnits = 0;
67    ctx->Const.MaxCombinedTextureImageUnits = 2;
68    ctx->Const.MaxTextureImageUnits = 2;
69    ctx->Const.FragmentProgram.MaxUniformComponents = 64;
70 
71    ctx->Const.MaxDrawBuffers = 2;
72 }
73 
74 /* Returned string will have 'ctx' as its hieralloc owner. */
75 static char *
load_text_file(void * ctx,const char * file_name)76 load_text_file(void *ctx, const char *file_name)
77 {
78 	char *text = NULL;
79 	struct stat st;
80 	ssize_t total_read = 0;
81 	int fd = open(file_name, O_RDONLY);
82 
83 	if (fd < 0) {
84 		return NULL;
85 	}
86 
87 	if (fstat(fd, & st) == 0) {
88 	   text = (char *) hieralloc_size(ctx, st.st_size + 1);
89 		if (text != NULL) {
90 			do {
91 				ssize_t bytes = read(fd, text + total_read,
92 						     st.st_size - total_read);
93 				if (bytes < 0) {
94 					free(text);
95 					text = NULL;
96 					break;
97 				}
98 
99 				if (bytes == 0) {
100 					break;
101 				}
102 
103 				total_read += bytes;
104 			} while (total_read < st.st_size);
105 
106 			text[total_read] = '\0';
107 		}
108 	}
109 
110 	close(fd);
111 
112 	return text;
113 }
114 
115 int glsl_es = 0;
116 int dump_ast = 0;
117 int dump_hir = 0;
118 int dump_lir = 0;
119 int do_link = 0;
120 
121 const struct option compiler_opts[] = {
122    { "glsl-es",  0, &glsl_es,  1 },
123    { "dump-ast", 0, &dump_ast, 1 },
124    { "dump-hir", 0, &dump_hir, 1 },
125    { "dump-lir", 0, &dump_lir, 1 },
126    { "link",     0, &do_link,  1 },
127    { NULL, 0, NULL, 0 }
128 };
129 
130 /**
131  * \brief Print proper usage and exit with failure.
132  */
133 void
usage_fail(const char * name)134 usage_fail(const char *name)
135 {
136 
137    const char *header =
138       "usage: %s [options] <file.vert | file.geom | file.frag>\n"
139       "\n"
140       "Possible options are:\n";
141    printf(header, name, name);
142    for (const struct option *o = compiler_opts; o->name != 0; ++o) {
143       printf("    --%s\n", o->name);
144    }
145    exit(EXIT_FAILURE);
146 }
147 
148 
149 void
compile_shader(struct gl_context * ctx,struct gl_shader * shader)150 compile_shader(struct gl_context *ctx, struct gl_shader *shader)
151 {
152    struct _mesa_glsl_parse_state *state =
153       new(shader) _mesa_glsl_parse_state(ctx, shader->Type, shader);
154 
155    const char *source = shader->Source;
156    state->error = preprocess(state, &source, &state->info_log,
157 			     state->extensions, ctx->API);
158 
159    if (!state->error) {
160       _mesa_glsl_lexer_ctor(state, source);
161       _mesa_glsl_parse(state);
162       _mesa_glsl_lexer_dtor(state);
163    }
164 
165    if (dump_ast) {
166       foreach_list_const(n, &state->translation_unit) {
167 	 ast_node *ast = exec_node_data(ast_node, n, link);
168 	 ast->print();
169       }
170       printf("\n\n");
171    }
172 
173    shader->ir = new(shader) exec_list;
174    if (!state->error && !state->translation_unit.is_empty())
175       _mesa_ast_to_hir(shader->ir, state);
176 
177    /* Print out the unoptimized IR. */
178    if (!state->error && dump_hir) {
179       validate_ir_tree(shader->ir);
180       _mesa_print_ir(shader->ir, state);
181    }
182 
183    /* Optimization passes */
184    if (!state->error && !shader->ir->is_empty()) {
185       bool progress;
186       do {
187 	 progress = do_common_optimization(shader->ir, false, 32);
188       } while (progress);
189 
190       validate_ir_tree(shader->ir);
191    }
192 
193 
194    /* Print out the resulting IR */
195    if (!state->error && dump_lir) {
196       _mesa_print_ir(shader->ir, state);
197    }
198 
199    shader->symbols = state->symbols;
200    shader->CompileStatus = !state->error;
201    shader->Version = state->language_version;
202    memcpy(shader->builtins_to_link, state->builtins_to_link,
203 	  sizeof(shader->builtins_to_link[0]) * state->num_builtins_to_link);
204    shader->num_builtins_to_link = state->num_builtins_to_link;
205 
206    if (shader->InfoLog)
207       hieralloc_free(shader->InfoLog);
208 
209    shader->InfoLog = state->info_log;
210 
211    /* Retain any live IR, but trash the rest. */
212    reparent_ir(shader->ir, shader);
213 
214    hieralloc_free(state);
215 
216    return;
217 }
218 
219 int
main(int argc,char ** argv)220 main(int argc, char **argv)
221 {
222    int status = EXIT_SUCCESS;
223    struct gl_context local_ctx;
224    struct gl_context *ctx = &local_ctx;
225 
226    int c;
227    int idx = 0;
228    while ((c = getopt_long(argc, argv, "", compiler_opts, &idx)) != -1)
229       /* empty */ ;
230 
231 
232    if (argc <= optind)
233       usage_fail(argv[0]);
234 
235    initialize_context(ctx, (glsl_es) ? API_OPENGLES2 : API_OPENGL);
236 
237    struct gl_shader_program *whole_program;
238 
239    whole_program = hieralloc_zero (NULL, struct gl_shader_program);
240    assert(whole_program != NULL);
241 
242    for (/* empty */; argc > optind; optind++) {
243       whole_program->Shaders = (struct gl_shader **)
244 	 hieralloc_realloc(whole_program, whole_program->Shaders,
245 			struct gl_shader *, whole_program->NumShaders + 1);
246       assert(whole_program->Shaders != NULL);
247 
248       struct gl_shader *shader = hieralloc_zero(whole_program, gl_shader);
249 
250       whole_program->Shaders[whole_program->NumShaders] = shader;
251       whole_program->NumShaders++;
252 
253       const unsigned len = strlen(argv[optind]);
254       if (len < 6)
255 	 usage_fail(argv[0]);
256 
257       const char *const ext = & argv[optind][len - 5];
258       if (strncmp(".vert", ext, 5) == 0)
259 	 shader->Type = GL_VERTEX_SHADER;
260       else if (strncmp(".geom", ext, 5) == 0)
261 	 shader->Type = GL_GEOMETRY_SHADER;
262       else if (strncmp(".frag", ext, 5) == 0)
263 	 shader->Type = GL_FRAGMENT_SHADER;
264       else
265 	 usage_fail(argv[0]);
266 
267       shader->Source = load_text_file(whole_program, argv[optind]);
268       if (shader->Source == NULL) {
269 	 printf("File \"%s\" does not exist.\n", argv[optind]);
270 	 exit(EXIT_FAILURE);
271       }
272 
273       compile_shader(ctx, shader);
274 
275       if (!shader->CompileStatus) {
276 	 printf("Info log for %s:\n%s\n", argv[optind], shader->InfoLog);
277 	 status = EXIT_FAILURE;
278 	 break;
279       }
280    }
281 
282    if ((status == EXIT_SUCCESS) && do_link)  {
283       link_shaders(ctx, whole_program);
284       status = (whole_program->LinkStatus) ? EXIT_SUCCESS : EXIT_FAILURE;
285 
286       if (strlen(whole_program->InfoLog) > 0)
287 	 printf("Info log for linking:\n%s\n", whole_program->InfoLog);
288    }
289 
290    for (unsigned i = 0; i < MESA_SHADER_TYPES; i++)
291       hieralloc_free(whole_program->_LinkedShaders[i]);
292 
293    hieralloc_free(whole_program);
294    _mesa_glsl_release_types();
295    _mesa_glsl_release_functions();
296 
297    return status;
298 }
299