nv50: fix build-predicate function
[mesa.git] / src / mesa / drivers / glslcompiler / glslcompiler.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5.3
4 *
5 * Copyright (C) 1999-2007 Brian Paul, Tungsten Graphics, Inc.
6 * All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26 /**
27 * \mainpage
28 *
29 * Stand-alone Shading Language compiler.
30 * Basically, a command-line program which accepts GLSL shaders and emits
31 * vertex/fragment programs (GPU instructions).
32 *
33 * This file is basically just a Mesa device driver but instead of building
34 * a shared library we build an executable.
35 *
36 * We can emit programs in three different formats:
37 * 1. ARB-style (GL_ARB_vertex/fragment_program)
38 * 2. NV-style (GL_NV_vertex/fragment_program)
39 * 3. debug-style (a slightly more sophisticated, internal format)
40 *
41 * Note that the ARB and NV program languages can't express all the
42 * features that might be used by a fragment program (examples being
43 * uniform and varying vars). So, the ARB/NV programs that are
44 * emitted aren't always legal programs in those languages.
45 */
46
47
48 #include "main/imports.h"
49 #include "main/context.h"
50 #include "main/extensions.h"
51 #include "main/framebuffer.h"
52 #include "main/shaderapi.h"
53 #include "main/shaderobj.h"
54 #include "program/prog_print.h"
55 #include "drivers/common/driverfuncs.h"
56 #include "tnl/tnl.h"
57 #include "tnl/t_context.h"
58 #include "tnl/t_pipeline.h"
59 #include "swrast/swrast.h"
60 #include "swrast_setup/swrast_setup.h"
61 #include "vbo/vbo.h"
62
63
64 static const char *Prog = "glslcompiler";
65
66
67 struct options {
68 GLboolean LineNumbers;
69 GLboolean Link;
70 gl_prog_print_mode Mode;
71 const char *VertFile;
72 const char *FragFile;
73 const char *GeoFile;
74 const char *OutputFile;
75 GLboolean Params;
76 struct gl_sl_pragmas Pragmas;
77 };
78
79 static struct options Options;
80
81
82 /**
83 * GLSL compiler driver context. (kind of an artificial thing for now)
84 */
85 struct compiler_context
86 {
87 GLcontext MesaContext;
88 int foo;
89 };
90
91 typedef struct compiler_context CompilerContext;
92
93
94
95 static void
96 UpdateState(GLcontext *ctx, GLuint new_state)
97 {
98 /* easy - just propogate */
99 _swrast_InvalidateState( ctx, new_state );
100 _swsetup_InvalidateState( ctx, new_state );
101 _tnl_InvalidateState( ctx, new_state );
102 _vbo_InvalidateState( ctx, new_state );
103 }
104
105
106
107 static GLboolean
108 CreateContext(void)
109 {
110 struct dd_function_table ddFuncs;
111 GLvisual *vis;
112 GLframebuffer *buf;
113 GLcontext *ctx;
114 CompilerContext *cc;
115
116 vis = _mesa_create_visual(GL_FALSE, GL_FALSE, /* RGB */
117 8, 8, 8, 8, /* color */
118 0, 0, /* z, stencil */
119 0, 0, 0, 0, 1); /* accum */
120 buf = _mesa_create_framebuffer(vis);
121
122 cc = calloc(1, sizeof(*cc));
123 if (!vis || !buf || !cc) {
124 if (vis)
125 _mesa_destroy_visual(vis);
126 if (buf)
127 _mesa_destroy_framebuffer(buf);
128 free(cc);
129 return GL_FALSE;
130 }
131
132 _mesa_init_driver_functions(&ddFuncs);
133 ddFuncs.GetString = NULL;/*get_string;*/
134 ddFuncs.UpdateState = UpdateState;
135 ddFuncs.GetBufferSize = NULL;
136
137 ctx = &cc->MesaContext;
138 _mesa_initialize_context(ctx, vis, NULL, &ddFuncs, cc);
139 _mesa_enable_sw_extensions(ctx);
140
141 if (!_swrast_CreateContext( ctx ) ||
142 !_vbo_CreateContext( ctx ) ||
143 !_tnl_CreateContext( ctx ) ||
144 !_swsetup_CreateContext( ctx )) {
145 _mesa_destroy_visual(vis);
146 _mesa_destroy_framebuffer(buf);
147 _mesa_free_context_data(ctx);
148 free(cc);
149 return GL_FALSE;
150 }
151 TNL_CONTEXT(ctx)->Driver.RunPipeline = _tnl_run_pipeline;
152 _swsetup_Wakeup( ctx );
153
154 /* Override the context's default pragma settings */
155 ctx->Shader.DefaultPragmas = Options.Pragmas;
156
157 _mesa_make_current(ctx, buf, buf);
158
159 return GL_TRUE;
160 }
161
162
163 static void
164 LoadAndCompileShader(GLuint shader, const char *text)
165 {
166 GLint stat;
167 _mesa_ShaderSourceARB(shader, 1, (const GLchar **) &text, NULL);
168 _mesa_CompileShaderARB(shader);
169 _mesa_GetShaderiv(shader, GL_COMPILE_STATUS, &stat);
170 if (!stat) {
171 GLchar log[1000];
172 GLsizei len;
173 _mesa_GetShaderInfoLog(shader, 1000, &len, log);
174 fprintf(stderr, "%s: problem compiling shader: %s\n", Prog, log);
175 exit(1);
176 }
177 else {
178 printf("Shader compiled OK\n");
179 }
180 }
181
182
183 /**
184 * Read a shader from a file.
185 */
186 static void
187 ReadShader(GLuint shader, const char *filename)
188 {
189 const int max = 100*1000;
190 int n;
191 char *buffer = (char*) malloc(max);
192 FILE *f = fopen(filename, "r");
193 if (!f) {
194 fprintf(stderr, "%s: Unable to open shader file %s\n", Prog, filename);
195 exit(1);
196 }
197
198 n = fread(buffer, 1, max, f);
199 /*
200 printf("%s: read %d bytes from shader file %s\n", Prog, n, filename);
201 */
202 if (n > 0) {
203 buffer[n] = 0;
204 LoadAndCompileShader(shader, buffer);
205 }
206
207 fclose(f);
208 free(buffer);
209 }
210
211
212 static void
213 CheckLink(GLuint v_shader, GLuint f_shader)
214 {
215 GLuint prog;
216 GLint stat;
217
218 prog = _mesa_CreateProgram();
219
220 _mesa_AttachShader(prog, v_shader);
221 _mesa_AttachShader(prog, f_shader);
222
223 _mesa_LinkProgramARB(prog);
224 _mesa_GetProgramiv(prog, GL_LINK_STATUS, &stat);
225 if (!stat) {
226 GLchar log[1000];
227 GLsizei len;
228 _mesa_GetProgramInfoLog(prog, 1000, &len, log);
229 fprintf(stderr, "Linker error:\n%s\n", log);
230 }
231 else {
232 fprintf(stderr, "Link success!\n");
233 }
234 }
235
236
237 static void
238 PrintShaderInstructions(GLuint shader, FILE *f)
239 {
240 GET_CURRENT_CONTEXT(ctx);
241 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
242 struct gl_program *prog = sh->Program;
243 _mesa_fprint_program_opt(stdout, prog, Options.Mode, Options.LineNumbers);
244 if (Options.Params)
245 _mesa_print_program_parameters(ctx, prog);
246 }
247
248
249 static GLuint
250 CompileShader(const char *filename, GLenum type)
251 {
252 GLuint shader;
253
254 assert(type == GL_FRAGMENT_SHADER ||
255 type == GL_VERTEX_SHADER ||
256 type == GL_GEOMETRY_SHADER_ARB);
257
258 shader = _mesa_CreateShader(type);
259 ReadShader(shader, filename);
260
261 return shader;
262 }
263
264
265 static void
266 Usage(void)
267 {
268 printf("Mesa GLSL stand-alone compiler\n");
269 printf("Usage:\n");
270 printf(" --vs FILE vertex shader input filename\n");
271 printf(" --fs FILE fragment shader input filename\n");
272 printf(" --gs FILE geometry shader input filename\n");
273 printf(" --arb emit ARB-style instructions\n");
274 printf(" --nv emit NV-style instructions\n");
275 printf(" --link run linker\n");
276 printf(" --debug force #pragma debug(on)\n");
277 printf(" --nodebug force #pragma debug(off)\n");
278 printf(" --opt force #pragma optimize(on)\n");
279 printf(" --noopt force #pragma optimize(off)\n");
280 printf(" --number, -n emit line numbers (if --arb or --nv)\n");
281 printf(" --output, -o FILE output filename\n");
282 printf(" --params also emit program parameter info\n");
283 printf(" --help display this information\n");
284 }
285
286
287 static void
288 ParseOptions(int argc, char *argv[])
289 {
290 int i;
291
292 Options.LineNumbers = GL_FALSE;
293 Options.Mode = PROG_PRINT_DEBUG;
294 Options.VertFile = NULL;
295 Options.FragFile = NULL;
296 Options.GeoFile = NULL;
297 Options.OutputFile = NULL;
298 Options.Params = GL_FALSE;
299 Options.Pragmas.IgnoreOptimize = GL_FALSE;
300 Options.Pragmas.IgnoreDebug = GL_FALSE;
301 Options.Pragmas.Debug = GL_FALSE;
302 Options.Pragmas.Optimize = GL_TRUE;
303
304 if (argc == 1) {
305 Usage();
306 exit(0);
307 }
308
309 for (i = 1; i < argc; i++) {
310 if (strcmp(argv[i], "--vs") == 0) {
311 Options.VertFile = argv[i + 1];
312 i++;
313 }
314 else if (strcmp(argv[i], "--fs") == 0) {
315 Options.FragFile = argv[i + 1];
316 i++;
317 }
318 else if (strcmp(argv[i], "--gs") == 0) {
319 Options.GeoFile = argv[i + 1];
320 i++;
321 }
322 else if (strcmp(argv[i], "--arb") == 0) {
323 Options.Mode = PROG_PRINT_ARB;
324 }
325 else if (strcmp(argv[i], "--nv") == 0) {
326 Options.Mode = PROG_PRINT_NV;
327 }
328 else if (strcmp(argv[i], "--link") == 0) {
329 Options.Link = GL_TRUE;
330 }
331 else if (strcmp(argv[i], "--debug") == 0) {
332 Options.Pragmas.IgnoreDebug = GL_TRUE;
333 Options.Pragmas.Debug = GL_TRUE;
334 }
335 else if (strcmp(argv[i], "--nodebug") == 0) {
336 Options.Pragmas.IgnoreDebug = GL_TRUE;
337 Options.Pragmas.Debug = GL_FALSE;
338 }
339 else if (strcmp(argv[i], "--opt") == 0) {
340 Options.Pragmas.IgnoreOptimize = GL_TRUE;
341 Options.Pragmas.Optimize = GL_TRUE;
342 }
343 else if (strcmp(argv[i], "--noopt") == 0) {
344 Options.Pragmas.IgnoreOptimize = GL_TRUE;
345 Options.Pragmas.Optimize = GL_FALSE;
346 }
347 else if (strcmp(argv[i], "--number") == 0 ||
348 strcmp(argv[i], "-n") == 0) {
349 Options.LineNumbers = GL_TRUE;
350 }
351 else if (strcmp(argv[i], "--output") == 0 ||
352 strcmp(argv[i], "-o") == 0) {
353 Options.OutputFile = argv[i + 1];
354 i++;
355 }
356 else if (strcmp(argv[i], "--params") == 0) {
357 Options.Params = GL_TRUE;
358 }
359 else if (strcmp(argv[i], "--help") == 0) {
360 Usage();
361 exit(0);
362 }
363 else {
364 printf("Unknown option: %s\n", argv[i]);
365 Usage();
366 exit(1);
367 }
368 }
369
370 if (Options.Mode == PROG_PRINT_DEBUG) {
371 /* always print line numbers when emitting debug-style output */
372 Options.LineNumbers = GL_TRUE;
373 }
374 }
375
376
377 int
378 main(int argc, char *argv[])
379 {
380 GLuint v_shader = 0, f_shader = 0, g_shader = 0;
381
382 ParseOptions(argc, argv);
383
384 if (!CreateContext()) {
385 fprintf(stderr, "%s: Failed to create compiler context\n", Prog);
386 exit(1);
387 }
388
389 if (Options.VertFile) {
390 v_shader = CompileShader(Options.VertFile, GL_VERTEX_SHADER);
391 }
392
393 if (Options.FragFile) {
394 f_shader = CompileShader(Options.FragFile, GL_FRAGMENT_SHADER);
395 }
396
397 if (Options.GeoFile) {
398 g_shader = CompileShader(Options.GeoFile, GL_GEOMETRY_SHADER_ARB);
399 }
400
401
402 if (v_shader || f_shader || g_shader) {
403 if (Options.OutputFile) {
404 FILE *f;
405 fclose(stdout);
406 /*stdout =*/ f = freopen(Options.OutputFile, "w", stdout);
407 if (!f) {
408 fprintf(stderr, "freopen error\n");
409 }
410 }
411 if (stdout && v_shader) {
412 PrintShaderInstructions(v_shader, stdout);
413 }
414 if (stdout && f_shader) {
415 PrintShaderInstructions(f_shader, stdout);
416 }
417 if (stdout && g_shader) {
418 PrintShaderInstructions(g_shader, stdout);
419 }
420 if (Options.OutputFile) {
421 fclose(stdout);
422 }
423 }
424
425 if (Options.Link) {
426 if (!v_shader || !f_shader) {
427 fprintf(stderr,
428 "--link option requires both a vertex and fragment shader.\n");
429 exit(1);
430 }
431
432 CheckLink(v_shader, f_shader);
433 }
434
435 return 0;
436 }