main.cpp revision d50d9a90a0df4d706421850e17c0fbd85bf710ee
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#include "ir_to_llvm.h"
41
42extern "C" struct gl_shader *
43_mesa_new_shader(struct gl_context *ctx, GLuint name, GLenum type);
44
45extern "C" void
46_mesa_reference_shader(struct gl_context *ctx, struct gl_shader **ptr,
47                       struct gl_shader *sh);
48
49/* Copied from shader_api.c for the stand-alone compiler.
50 */
51void
52_mesa_reference_shader(struct gl_context *ctx, struct gl_shader **ptr,
53                       struct gl_shader *sh)
54{
55   *ptr = sh;
56}
57
58struct gl_shader *
59_mesa_new_shader(struct gl_context *ctx, GLuint name, GLenum type)
60{
61   struct gl_shader *shader;
62
63   (void) ctx;
64
65   assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER);
66   shader = hieralloc_zero(NULL, struct gl_shader);
67   if (shader) {
68      shader->Type = type;
69      shader->Name = name;
70      shader->RefCount = 1;
71   }
72   return shader;
73}
74
75static void
76initialize_context(struct gl_context *ctx, gl_api api)
77{
78   memset(ctx, 0, sizeof(*ctx));
79
80   ctx->API = api;
81
82   ctx->Extensions.ARB_draw_buffers = GL_TRUE;
83   ctx->Extensions.ARB_fragment_coord_conventions = GL_TRUE;
84   ctx->Extensions.EXT_texture_array = GL_TRUE;
85   ctx->Extensions.NV_texture_rectangle = GL_TRUE;
86
87   /* 1.10 minimums. */
88   ctx->Const.MaxLights = 8;
89   ctx->Const.MaxClipPlanes = 8;
90   ctx->Const.MaxTextureUnits = 2;
91
92   /* More than the 1.10 minimum to appease parser tests taken from
93    * apps that (hopefully) already checked the number of coords.
94    */
95   ctx->Const.MaxTextureCoordUnits = 4;
96
97   ctx->Const.VertexProgram.MaxAttribs = 16;
98   ctx->Const.VertexProgram.MaxUniformComponents = 512;
99   ctx->Const.MaxVarying = 8;
100   ctx->Const.MaxVertexTextureImageUnits = 0;
101   ctx->Const.MaxCombinedTextureImageUnits = 2;
102   ctx->Const.MaxTextureImageUnits = 2;
103   ctx->Const.FragmentProgram.MaxUniformComponents = 64;
104
105   ctx->Const.MaxDrawBuffers = 2;
106
107   ctx->Driver.NewShader = _mesa_new_shader;
108}
109
110/* Returned string will have 'ctx' as its hieralloc owner. */
111static char *
112load_text_file(void *ctx, const char *file_name)
113{
114	char *text = NULL;
115	struct stat st;
116	ssize_t total_read = 0;
117	int fd = open(file_name, O_RDONLY);
118
119	if (fd < 0) {
120		return NULL;
121	}
122
123	if (fstat(fd, & st) == 0) {
124	   text = (char *) hieralloc_size(ctx, st.st_size + 1);
125		if (text != NULL) {
126			do {
127				ssize_t bytes = read(fd, text + total_read,
128						     st.st_size - total_read);
129				if (bytes < 0) {
130					free(text);
131					text = NULL;
132					break;
133				}
134
135				if (bytes == 0) {
136					break;
137				}
138
139				total_read += bytes;
140			} while (total_read < st.st_size);
141
142			text[total_read] = '\0';
143		}
144	}
145
146	close(fd);
147
148	return text;
149}
150
151int glsl_es = 0;
152int dump_ast = 0;
153int dump_hir = 0;
154int dump_lir = 0;
155int do_link = 0;
156int do_jit = 0;
157
158const struct option compiler_opts[] = {
159   { "glsl-es",  0, &glsl_es,  1 },
160   { "dump-ast", 0, &dump_ast, 1 },
161   { "dump-hir", 0, &dump_hir, 1 },
162   { "dump-lir", 0, &dump_lir, 1 },
163   { "link",     0, &do_link,  1 },
164   { "do-jit",   0, &do_jit,   1 },
165   { NULL, 0, NULL, 0 }
166};
167
168/**
169 * \brief Print proper usage and exit with failure.
170 */
171void
172usage_fail(const char *name)
173{
174
175   const char *header =
176      "usage: %s [options] <file.vert | file.geom | file.frag>\n"
177      "\n"
178      "Possible options are:\n";
179   printf(header, name, name);
180   for (const struct option *o = compiler_opts; o->name != 0; ++o) {
181      printf("    --%s\n", o->name);
182   }
183   exit(EXIT_FAILURE);
184}
185
186
187void
188compile_shader(struct gl_context *ctx, struct gl_shader *shader)
189{
190   struct _mesa_glsl_parse_state *state =
191      new(shader) _mesa_glsl_parse_state(ctx, shader->Type, shader);
192
193   const char *source = shader->Source;
194   state->error = preprocess(state, &source, &state->info_log,
195			     state->extensions, ctx->API);
196
197   if (!state->error) {
198      _mesa_glsl_lexer_ctor(state, source);
199      _mesa_glsl_parse(state);
200      _mesa_glsl_lexer_dtor(state);
201   }
202
203   if (dump_ast) {
204      foreach_list_const(n, &state->translation_unit) {
205	 ast_node *ast = exec_node_data(ast_node, n, link);
206	 ast->print();
207      }
208      printf("\n\n");
209   }
210
211   shader->ir = new(shader) exec_list;
212   if (!state->error && !state->translation_unit.is_empty())
213      _mesa_ast_to_hir(shader->ir, state);
214
215   /* Print out the unoptimized IR. */
216   if (!state->error && dump_hir) {
217      validate_ir_tree(shader->ir);
218      _mesa_print_ir(shader->ir, state);
219   }
220
221   /* Optimization passes */
222   if (!state->error && !shader->ir->is_empty()) {
223      bool progress;
224      do {
225	 progress = do_common_optimization(shader->ir, false, 32);
226      } while (progress);
227
228      validate_ir_tree(shader->ir);
229   }
230
231
232   /* Print out the resulting IR */
233   if (!state->error && dump_lir) {
234      _mesa_print_ir(shader->ir, state);
235   }
236
237   shader->symbols = state->symbols;
238   shader->CompileStatus = !state->error;
239   shader->Version = state->language_version;
240   memcpy(shader->builtins_to_link, state->builtins_to_link,
241	  sizeof(shader->builtins_to_link[0]) * state->num_builtins_to_link);
242   shader->num_builtins_to_link = state->num_builtins_to_link;
243
244   if (shader->InfoLog)
245      hieralloc_free(shader->InfoLog);
246
247   shader->InfoLog = state->info_log;
248
249   /* Retain any live IR, but trash the rest. */
250   reparent_ir(shader->ir, shader);
251
252   hieralloc_free(state);
253
254   return;
255}
256
257
258#include "image_file.h"
259
260void execute(void (* function)(), float * data)
261{
262   const unsigned width = 480, height = 800;
263   const unsigned wd = 200, ht = 200;
264   unsigned * frameSurface = new unsigned [width * height];
265   float * constants = data + 36;
266   float * outputs = data + 0;
267   float * inputs = data + 12;
268   printf("executing... \n function=%p, data=%p \n", function, data);
269
270   /*
271   #ifdef __arm__
272   {
273      volatile unsigned wait = 1;
274      printf("waiting for attach, set wait(%p) to 0 \n", &wait);
275      puts("");
276      while (wait);
277   }
278   #endif
279   //*/
280
281   unsigned frames = 1;
282
283   clock_t c0 = clock();
284   //for (unsigned i = 0; i < 480 * 800; i++)
285   for (unsigned y = 0; y < ht; y++)
286      for (unsigned x = 0; x < wd; x++) {
287         //data[36] = (float)i / 10000;
288         //memset(data, i, sizeof(data));
289         inputs[0] = ((float)x) / wd;
290         inputs[1] = ((float)y) / ht;
291         inputs[2] = 0;
292         inputs[3] = 1;
293         constants[0] = 0.0f;
294         function();
295         unsigned r = outputs[0] * 255;
296         unsigned g = outputs[1] * 255;
297         unsigned b = outputs[2] * 255;
298         unsigned a = outputs[3] * 255;
299         frameSurface[y * width + x] = (a << 24) | (b << 16) | (g << 8) | r;
300
301      }
302
303   float elapsed = (float)(clock() - c0) / CLOCKS_PER_SEC;
304   printf ("\n *** test_scan elapsed CPU time: %fs \n *** fps=%.2f, tpf=%.2fms \n",
305           elapsed, frames / elapsed, elapsed / frames * 1000);
306   printf("gl_FragColor=%.2f, %.2f, %.2f %.2f \n", outputs[0], outputs[1], outputs[2], outputs[3]);
307#ifdef __arm__
308   SaveBMP("/sdcard/mesa.bmp", frameSurface, width, height);
309#else
310   SaveBMP("mesa.bmp", frameSurface, width, height);
311#endif
312   delete frameSurface;
313}
314
315//#def USE_LLVM_EXECUTIONENGINE 1
316#if USE_LLVM_EXECUTIONENGINE
317
318#include <llvm/ExecutionEngine/JIT.h>
319#include <llvm/Target/TargetSelect.h>
320
321void jit(llvm::Module * mod)
322{
323#ifndef __arm__
324   __attribute__ ((aligned (16))) // LLVM generates movaps on X86, needs 16 bytes align
325#endif
326   float data [64];
327   memset(data, 0xff, sizeof(data));
328
329   llvm::InitializeNativeTarget();
330
331   std::string errorString;
332   llvm::EngineBuilder engineBuilder(mod);
333   engineBuilder.setEngineKind(llvm::EngineKind::JIT);
334   engineBuilder.setErrorStr(&errorString);
335#ifdef __arm__
336   engineBuilder.setMAttrs(llvm::SmallVector<std::string, 1>(1,"vfp3"));
337   mod->setTargetTriple("armv7-none-linux-gnueabi");
338#endif
339
340   llvm::ExecutionEngine * ee = engineBuilder.create();
341   if (!ee)
342      puts(errorString.c_str());
343   assert(ee);
344
345   ee->DisableLazyCompilation();
346
347   if ((mod->getFunction("putchar")))
348      ee->updateGlobalMapping(mod->getFunction("putchar"), (void *)putchar);
349   if ((mod->getFunction("sinf")))
350      ee->updateGlobalMapping(mod->getFunction("sinf"), (void *)sinf);
351   if ((mod->getFunction("cosf")))
352      ee->updateGlobalMapping(mod->getFunction("cosf"), (void *)cosf);
353   if ((mod->getFunction("powf")))
354      ee->updateGlobalMapping(mod->getFunction("powf"), (void *)cosf);
355
356   ee->updateGlobalMapping(mod->getGlobalVariable("gl_FragColor"), (void *)(data + 0));
357   ee->updateGlobalMapping(mod->getGlobalVariable("gl_FragCoord"), (void *)(data + 4));
358   ee->updateGlobalMapping(mod->getGlobalVariable("gl_FrontFacing"), (void *)(data + 8));
359   ee->updateGlobalMapping(mod->getGlobalVariable("vTexCoord"), (void *)(data + 12));
360   ee->updateGlobalMapping(mod->getGlobalVariable("t"), (void *)(data + 36));
361
362   llvm::Function * func = mod->getFunction("main");
363   assert(func);
364
365   void (* function)() = (void (*)())ee->getPointerToFunction(func);
366   execute(function, data);
367   puts("USE_LLVM_EXECUTIONENGINE");
368   printf("gl_FragColor=%.2f, %.2f, %.2f %.2f \n", data[0], data[1], data[2], data[3]);
369}
370
371#else
372
373#include <bcc/bcc.h>
374#include <dlfcn.h>
375
376static void* symbolLookup(void* pContext, const char* name)
377{
378   float * data = (float *)pContext;
379   void * symbol = (void*)dlsym(RTLD_DEFAULT, name);
380   if (NULL == symbol) {
381      if (0 == strcmp("gl_FragColor", name))
382         symbol = data + 0;
383      else if (0 == strcmp("gl_FragCoord", name))
384         symbol = data + 4;
385      else if (0 == strcmp("gl_FrontFacing", name))
386         symbol = data + 8;
387      else if (0 == strcmp("vTexCoord", name)) {
388         symbol = data + 12;
389         *(data + 12) = 1.1;
390         *(data + 13) = 1.2;
391         *(data + 14) = 1.3;
392         *(data + 15) = 1;
393      } else if (0 == strcmp("uRotM", name)) {
394         symbol = data + 16;
395         memset(data + 16, 0, 16 * sizeof(*data));
396         data[16] = data[21] = data[26] = data[31] = 1;
397         data[28] = 11;
398         data[29] = 22;
399         data[30] = 33;
400         //data[31] = 44;
401      } else if (0 == strcmp("uFragmentColor", name)) {
402         symbol = data + 32;
403         data[32] = 1.57075f;
404         data[33] = 1.57075f;
405         data[34] = 1.57075f;
406         data[35] = 1.57075f;
407      } else if (0 == strcmp("t", name)) {
408         symbol = data + 36;
409         data[36] = 0.1f;
410      }
411
412   }
413   printf("symbolLookup '%s'=%p \n", name, symbol);
414   assert(symbol);
415   return symbol;
416}
417
418void jit(llvm::Module * mod)
419{
420#ifndef __arm__
421   __attribute__ ((aligned (16))) // LLVM generates movaps on X86, needs 16 bytes align
422#endif
423   float data [64];
424   memset(data, 0xff, sizeof(data));
425
426   BCCScriptRef script = bccCreateScript();
427   bccReadModule(script, "glsl", (LLVMModuleRef)mod, 0);
428   int result = 0;
429   assert(0 == bccGetError(script));
430   bccRegisterSymbolCallback(script, symbolLookup, data);
431   assert(0 == bccGetError(script));
432   bccPrepareExecutable(script, NULL, 0);
433   result = bccGetError(script);
434   if (result != 0) {
435      puts("failed bcc_compile");
436      assert(0);
437      return;
438   }
439
440   void (* function)() = (void (*)())bccGetFuncAddr(script, "main");
441   result = bccGetError(script);
442   if (result != BCC_NO_ERROR)
443      fprintf(stderr, "Could not find '%s': %d\n", "main", result);
444   else
445      printf("bcc_compile %s=%p \n", "main", function);
446   execute(function, data);
447}
448
449#endif
450
451struct _mesa_glsl_parse_state * global_state = NULL;
452
453int
454main(int argc, char **argv)
455{
456   //*
457   if (1 == argc) {
458      argc = 6;
459      char shader_file_path[256] = {0};
460      memcpy(shader_file_path, argv[0], strlen(argv[0]));
461      char * slash = shader_file_path + strlen(shader_file_path);
462      while (*slash != '/')
463         slash--;
464      const char shader_file[] = "stress_fs.frag";
465      memcpy(slash + 1, shader_file, strlen(shader_file));
466      const char * args [] = {argv[0], "--dump-hir", "--do-jit", "--link", "--glsl-es", shader_file_path};
467      argv = (char **)args;
468   }
469   //*/
470   int status = EXIT_SUCCESS;
471   struct gl_context local_ctx;
472   struct gl_context *ctx = &local_ctx;
473
474   int c;
475   int idx = 0;
476   while ((c = getopt_long(argc, argv, "", compiler_opts, &idx)) != -1)
477      /* empty */ ;
478
479
480   if (argc <= optind)
481      usage_fail(argv[0]);
482
483   initialize_context(ctx, (glsl_es) ? API_OPENGLES2 : API_OPENGL);
484
485   struct gl_shader_program *whole_program;
486
487   whole_program = hieralloc_zero (NULL, struct gl_shader_program);
488   assert(whole_program != NULL);
489
490   for (/* empty */; argc > optind; optind++) {
491      whole_program->Shaders = (struct gl_shader **)
492         hieralloc_realloc(whole_program, whole_program->Shaders,
493         struct gl_shader *, whole_program->NumShaders + 1);
494      assert(whole_program->Shaders != NULL);
495
496      struct gl_shader *shader = hieralloc_zero(whole_program, gl_shader);
497
498      whole_program->Shaders[whole_program->NumShaders] = shader;
499      whole_program->NumShaders++;
500
501      const unsigned len = strlen(argv[optind]);
502      if (len < 6)
503	 usage_fail(argv[0]);
504
505      const char *const ext = & argv[optind][len - 5];
506      if (strncmp(".vert", ext, 5) == 0)
507	 shader->Type = GL_VERTEX_SHADER;
508      else if (strncmp(".geom", ext, 5) == 0)
509	 shader->Type = GL_GEOMETRY_SHADER;
510      else if (strncmp(".frag", ext, 5) == 0)
511	 shader->Type = GL_FRAGMENT_SHADER;
512      else
513	 usage_fail(argv[0]);
514
515      shader->Source = load_text_file(whole_program, argv[optind]);
516      if (shader->Source == NULL) {
517	 printf("File \"%s\" does not exist.\n", argv[optind]);
518	 exit(EXIT_FAILURE);
519      }
520
521      compile_shader(ctx, shader);
522
523      if (!shader->CompileStatus) {
524	 printf("Info log for %s:\n%s\n", argv[optind], shader->InfoLog);
525	 status = EXIT_FAILURE;
526	 break;
527      }
528   }
529
530   if ((status == EXIT_SUCCESS) && do_link)  {
531      link_shaders(ctx, whole_program);
532      status = (whole_program->LinkStatus) ? EXIT_SUCCESS : EXIT_FAILURE;
533
534      if (strlen(whole_program->InfoLog) > 0)
535         printf("Info log for linking:\n%s\n", whole_program->InfoLog);
536   }
537
538   puts("jit");
539
540   for (unsigned i = 0; do_jit && i < MESA_SHADER_TYPES; i++) {
541      struct gl_shader *shader = whole_program->_LinkedShaders[i];
542      if (!shader)
543         continue;
544      global_state = new(shader) _mesa_glsl_parse_state(ctx, shader->Type, shader);
545      exec_list * ir = shader->ir;
546
547      do_mat_op_to_vec(ir);
548
549      puts("\n *** IR for JIT *** \n");
550      _mesa_print_ir(ir, global_state);
551
552      llvm::Module * module = glsl_ir_to_llvm_module(ir);
553      assert(module);
554      puts("module translated");
555      jit(module);
556      puts("jitted");
557   }
558
559   for (unsigned i = 0; i < MESA_SHADER_TYPES; i++)
560      hieralloc_free(whole_program->_LinkedShaders[i]);
561
562   hieralloc_free(whole_program);
563   _mesa_glsl_release_types();
564   _mesa_glsl_release_functions();
565
566   puts("mesa exit");
567   hieralloc_report(NULL, stdout);
568   return status;
569}
570