diff options
Diffstat (limited to 'src/mesa/drivers/glslcompiler/glslcompiler.c')
-rw-r--r-- | src/mesa/drivers/glslcompiler/glslcompiler.c | 416 |
1 files changed, 416 insertions, 0 deletions
diff --git a/src/mesa/drivers/glslcompiler/glslcompiler.c b/src/mesa/drivers/glslcompiler/glslcompiler.c new file mode 100644 index 0000000000..d58f32b293 --- /dev/null +++ b/src/mesa/drivers/glslcompiler/glslcompiler.c @@ -0,0 +1,416 @@ +/* + * Mesa 3-D graphics library + * Version: 6.5.3 + * + * Copyright (C) 1999-2007 Brian Paul, Tungsten Graphics, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * \mainpage + * + * Stand-alone Shading Language compiler. + * Basically, a command-line program which accepts GLSL shaders and emits + * vertex/fragment programs (GPU instructions). + * + * This file is basically just a Mesa device driver but instead of building + * a shared library we build an executable. + * + * We can emit programs in three different formats: + * 1. ARB-style (GL_ARB_vertex/fragment_program) + * 2. NV-style (GL_NV_vertex/fragment_program) + * 3. debug-style (a slightly more sophisticated, internal format) + * + * Note that the ARB and NV program languages can't express all the + * features that might be used by a fragment program (examples being + * uniform and varying vars). So, the ARB/NV programs that are + * emitted aren't always legal programs in those languages. + */ + + +#include "main/imports.h" +#include "main/context.h" +#include "main/extensions.h" +#include "main/framebuffer.h" +#include "main/shaders.h" +#include "shader/shader_api.h" +#include "shader/prog_print.h" +#include "drivers/common/driverfuncs.h" +#include "tnl/tnl.h" +#include "tnl/t_context.h" +#include "tnl/t_pipeline.h" +#include "swrast/swrast.h" +#include "swrast/s_context.h" +#include "swrast/s_triangle.h" +#include "swrast_setup/swrast_setup.h" +#include "vbo/vbo.h" + + +static const char *Prog = "glslcompiler"; + + +struct options { + GLboolean LineNumbers; + GLboolean Link; + gl_prog_print_mode Mode; + const char *VertFile; + const char *FragFile; + const char *OutputFile; + GLboolean Params; + struct gl_sl_pragmas Pragmas; +}; + +static struct options Options; + + +/** + * GLSL compiler driver context. (kind of an artificial thing for now) + */ +struct compiler_context +{ + GLcontext MesaContext; + int foo; +}; + +typedef struct compiler_context CompilerContext; + + + +static void +UpdateState(GLcontext *ctx, GLuint new_state) +{ + /* easy - just propogate */ + _swrast_InvalidateState( ctx, new_state ); + _swsetup_InvalidateState( ctx, new_state ); + _tnl_InvalidateState( ctx, new_state ); + _vbo_InvalidateState( ctx, new_state ); +} + + + +static GLboolean +CreateContext(void) +{ + struct dd_function_table ddFuncs; + GLvisual *vis; + GLframebuffer *buf; + GLcontext *ctx; + CompilerContext *cc; + + vis = _mesa_create_visual(GL_FALSE, GL_FALSE, /* RGB */ + 8, 8, 8, 8, /* color */ + 0, 0, /* z, stencil */ + 0, 0, 0, 0, 1); /* accum */ + buf = _mesa_create_framebuffer(vis); + + cc = calloc(1, sizeof(*cc)); + if (!vis || !buf || !cc) { + if (vis) + _mesa_destroy_visual(vis); + if (buf) + _mesa_destroy_framebuffer(buf); + return GL_FALSE; + } + + _mesa_init_driver_functions(&ddFuncs); + ddFuncs.GetString = NULL;/*get_string;*/ + ddFuncs.UpdateState = UpdateState; + ddFuncs.GetBufferSize = NULL; + + ctx = &cc->MesaContext; + _mesa_initialize_context(ctx, vis, NULL, &ddFuncs, cc); + _mesa_enable_sw_extensions(ctx); + + if (!_swrast_CreateContext( ctx ) || + !_vbo_CreateContext( ctx ) || + !_tnl_CreateContext( ctx ) || + !_swsetup_CreateContext( ctx )) { + _mesa_destroy_visual(vis); + _mesa_free_context_data(ctx); + free(cc); + return GL_FALSE; + } + TNL_CONTEXT(ctx)->Driver.RunPipeline = _tnl_run_pipeline; + _swsetup_Wakeup( ctx ); + + /* Override the context's default pragma settings */ + ctx->Shader.DefaultPragmas = Options.Pragmas; + + _mesa_make_current(ctx, buf, buf); + + return GL_TRUE; +} + + +static void +LoadAndCompileShader(GLuint shader, const char *text) +{ + GLint stat; + _mesa_ShaderSourceARB(shader, 1, (const GLchar **) &text, NULL); + _mesa_CompileShaderARB(shader); + _mesa_GetShaderiv(shader, GL_COMPILE_STATUS, &stat); + if (!stat) { + GLchar log[1000]; + GLsizei len; + _mesa_GetShaderInfoLog(shader, 1000, &len, log); + fprintf(stderr, "%s: problem compiling shader: %s\n", Prog, log); + exit(1); + } + else { + printf("Shader compiled OK\n"); + } +} + + +/** + * Read a shader from a file. + */ +static void +ReadShader(GLuint shader, const char *filename) +{ + const int max = 100*1000; + int n; + char *buffer = (char*) malloc(max); + FILE *f = fopen(filename, "r"); + if (!f) { + fprintf(stderr, "%s: Unable to open shader file %s\n", Prog, filename); + exit(1); + } + + n = fread(buffer, 1, max, f); + /* + printf("%s: read %d bytes from shader file %s\n", Prog, n, filename); + */ + if (n > 0) { + buffer[n] = 0; + LoadAndCompileShader(shader, buffer); + } + + fclose(f); + free(buffer); +} + + +static void +CheckLink(GLuint v_shader, GLuint f_shader) +{ + GLuint prog; + GLint stat; + + prog = _mesa_CreateProgram(); + + _mesa_AttachShader(prog, v_shader); + _mesa_AttachShader(prog, f_shader); + + _mesa_LinkProgramARB(prog); + _mesa_GetProgramiv(prog, GL_LINK_STATUS, &stat); + if (!stat) { + GLchar log[1000]; + GLsizei len; + _mesa_GetProgramInfoLog(prog, 1000, &len, log); + fprintf(stderr, "Linker error:\n%s\n", log); + } + else { + fprintf(stderr, "Link success!\n"); + } +} + + +static void +PrintShaderInstructions(GLuint shader, FILE *f) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_shader *sh = _mesa_lookup_shader(ctx, shader); + struct gl_program *prog = sh->Program; + _mesa_fprint_program_opt(stdout, prog, Options.Mode, Options.LineNumbers); + if (Options.Params) + _mesa_print_program_parameters(ctx, prog); +} + + +static GLuint +CompileShader(const char *filename, GLenum type) +{ + GLuint shader; + + assert(type == GL_FRAGMENT_SHADER || + type == GL_VERTEX_SHADER); + + shader = _mesa_CreateShader(type); + ReadShader(shader, filename); + + return shader; +} + + +static void +Usage(void) +{ + printf("Mesa GLSL stand-alone compiler\n"); + printf("Usage:\n"); + printf(" --vs FILE vertex shader input filename\n"); + printf(" --fs FILE fragment shader input filename\n"); + printf(" --arb emit ARB-style instructions\n"); + printf(" --nv emit NV-style instructions\n"); + printf(" --link run linker\n"); + printf(" --debug force #pragma debug(on)\n"); + printf(" --nodebug force #pragma debug(off)\n"); + printf(" --opt force #pragma optimize(on)\n"); + printf(" --noopt force #pragma optimize(off)\n"); + printf(" --number, -n emit line numbers (if --arb or --nv)\n"); + printf(" --output, -o FILE output filename\n"); + printf(" --params also emit program parameter info\n"); + printf(" --help display this information\n"); +} + + +static void +ParseOptions(int argc, char *argv[]) +{ + int i; + + Options.LineNumbers = GL_FALSE; + Options.Mode = PROG_PRINT_DEBUG; + Options.VertFile = NULL; + Options.FragFile = NULL; + Options.OutputFile = NULL; + Options.Params = GL_FALSE; + Options.Pragmas.IgnoreOptimize = GL_FALSE; + Options.Pragmas.IgnoreDebug = GL_FALSE; + Options.Pragmas.Debug = GL_FALSE; + Options.Pragmas.Optimize = GL_TRUE; + + if (argc == 1) { + Usage(); + exit(0); + } + + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "--vs") == 0) { + Options.VertFile = argv[i + 1]; + i++; + } + else if (strcmp(argv[i], "--fs") == 0) { + Options.FragFile = argv[i + 1]; + i++; + } + else if (strcmp(argv[i], "--arb") == 0) { + Options.Mode = PROG_PRINT_ARB; + } + else if (strcmp(argv[i], "--nv") == 0) { + Options.Mode = PROG_PRINT_NV; + } + else if (strcmp(argv[i], "--link") == 0) { + Options.Link = GL_TRUE; + } + else if (strcmp(argv[i], "--debug") == 0) { + Options.Pragmas.IgnoreDebug = GL_TRUE; + Options.Pragmas.Debug = GL_TRUE; + } + else if (strcmp(argv[i], "--nodebug") == 0) { + Options.Pragmas.IgnoreDebug = GL_TRUE; + Options.Pragmas.Debug = GL_FALSE; + } + else if (strcmp(argv[i], "--opt") == 0) { + Options.Pragmas.IgnoreOptimize = GL_TRUE; + Options.Pragmas.Optimize = GL_TRUE; + } + else if (strcmp(argv[i], "--noopt") == 0) { + Options.Pragmas.IgnoreOptimize = GL_TRUE; + Options.Pragmas.Optimize = GL_FALSE; + } + else if (strcmp(argv[i], "--number") == 0 || + strcmp(argv[i], "-n") == 0) { + Options.LineNumbers = GL_TRUE; + } + else if (strcmp(argv[i], "--output") == 0 || + strcmp(argv[i], "-o") == 0) { + Options.OutputFile = argv[i + 1]; + i++; + } + else if (strcmp(argv[i], "--params") == 0) { + Options.Params = GL_TRUE; + } + else if (strcmp(argv[i], "--help") == 0) { + Usage(); + exit(0); + } + else { + printf("Unknown option: %s\n", argv[i]); + Usage(); + exit(1); + } + } + + if (Options.Mode == PROG_PRINT_DEBUG) { + /* always print line numbers when emitting debug-style output */ + Options.LineNumbers = GL_TRUE; + } +} + + +int +main(int argc, char *argv[]) +{ + GLuint v_shader = 0, f_shader = 0; + + ParseOptions(argc, argv); + + if (!CreateContext()) { + fprintf(stderr, "%s: Failed to create compiler context\n", Prog); + exit(1); + } + + if (Options.VertFile) { + v_shader = CompileShader(Options.VertFile, GL_VERTEX_SHADER); + } + + if (Options.FragFile) { + f_shader = CompileShader(Options.FragFile, GL_FRAGMENT_SHADER); + } + + if (v_shader || f_shader) { + if (Options.OutputFile) { + fclose(stdout); + /*stdout =*/ freopen(Options.OutputFile, "w", stdout); + } + if (stdout && v_shader) { + PrintShaderInstructions(v_shader, stdout); + } + if (stdout && f_shader) { + PrintShaderInstructions(f_shader, stdout); + } + if (Options.OutputFile) { + fclose(stdout); + } + } + + if (Options.Link) { + if (!v_shader || !f_shader) { + fprintf(stderr, + "--link option requires both a vertex and fragment shader.\n"); + exit(1); + } + + CheckLink(v_shader, f_shader); + } + + return 0; +} |