Home | History | Annotate | Download | only in tools
      1 #!/usr/bin/python
      2 # -*- coding: utf-8 -*-
      3 
      4 from __future__ import with_statement
      5 
      6 import re
      7 import sys
      8 from glob import glob
      9 from os import path
     10 from subprocess import Popen, PIPE
     11 from sys import argv
     12 
     13 # Local module: generator for texture lookup builtins
     14 from texture_builtins import generate_texture_functions
     15 
     16 builtins_dir = path.join(path.dirname(path.abspath(__file__)), "..")
     17 
     18 # Get the path to the standalone GLSL compiler
     19 if len(argv) != 2:
     20     print "Usage:", argv[0], "<path to compiler>"
     21     sys.exit(1)
     22 
     23 compiler = argv[1]
     24 
     25 # Read the files in builtins/ir/*...add them to the supplied dictionary.
     26 def read_ir_files(fs):
     27     for filename in glob(path.join(path.join(builtins_dir, 'ir'), '*.ir')):
     28         function_name = path.basename(filename).split('.')[0]
     29         with open(filename) as f:
     30             fs[function_name] = f.read()
     31 
     32 def read_glsl_files(fs):
     33     for filename in glob(path.join(path.join(builtins_dir, 'glsl'), '*.glsl')):
     34         function_name = path.basename(filename).split('.')[0]
     35         (output, returncode) = run_compiler([filename])
     36         if (returncode):
     37             sys.stderr.write("Failed to compile builtin: " + filename + "\n")
     38             sys.stderr.write("Result:\n")
     39             sys.stderr.write(output)
     40         else:
     41             fs[function_name] = output;
     42 
     43 # Return a dictionary containing all builtin definitions (even generated)
     44 def get_builtin_definitions():
     45     fs = {}
     46     generate_texture_functions(fs)
     47     read_ir_files(fs)
     48     read_glsl_files(fs)
     49     return fs
     50 
     51 def stringify(s):
     52     # Work around MSVC's 65535 byte limit by outputting an array of characters
     53     # rather than actual string literals.
     54     if len(s) >= 65535:
     55         #t = "/* Warning: length " + repr(len(s)) + " too large */\n"
     56         t = ""
     57         for c in re.sub('\s\s+', ' ', s):
     58             if c == '\n':
     59                 t += '\n'
     60             else:
     61                 t += "'" + c + "',"
     62         return '{' + t[:-1] + '}'
     63 
     64     t = s.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n"\n   "')
     65     return '   "' + t + '"\n'
     66 
     67 def write_function_definitions():
     68     fs = get_builtin_definitions()
     69     for k, v in sorted(fs.iteritems()):
     70         print 'static const char builtin_' + k + '[] ='
     71         print stringify(v), ';'
     72 
     73 def run_compiler(args):
     74     command = [compiler, '--dump-hir'] + args
     75     p = Popen(command, 1, stdout=PIPE, shell=False)
     76     output = p.communicate()[0]
     77 
     78     if (p.returncode):
     79         sys.stderr.write("Failed to compile builtins with command:\n")
     80         for arg in command:
     81             sys.stderr.write(arg + " ")
     82         sys.stderr.write("\n")
     83         sys.stderr.write("Result:\n")
     84         sys.stderr.write(output)
     85 
     86     # Clean up output a bit by killing whitespace before a closing paren.
     87     kill_paren_whitespace = re.compile(r'[ \n]*\)', re.MULTILINE)
     88     output = kill_paren_whitespace.sub(')', output)
     89 
     90     # Also toss any duplicate newlines
     91     output = output.replace('\n\n', '\n')
     92 
     93     # Kill any global variable declarations.  We don't want them.
     94     kill_globals = re.compile(r'^\(declare.*\n', re.MULTILINE)
     95     output = kill_globals.sub('', output)
     96 
     97     return (output, p.returncode)
     98 
     99 def write_profile(filename, profile):
    100     (proto_ir, returncode) = run_compiler([filename])
    101 
    102     if returncode != 0:
    103         print '#error builtins profile', profile, 'failed to compile'
    104         return
    105 
    106     print 'static const char prototypes_for_' + profile + '[] ='
    107     print stringify(proto_ir), ';'
    108 
    109     # Print a table of all the functions (not signatures) referenced.
    110     # This is done so we can avoid bothering with a hash table in the C++ code.
    111 
    112     function_names = set()
    113     for func in re.finditer(r'\(function (.+)\n', proto_ir):
    114         function_names.add(func.group(1))
    115 
    116     print 'static const char *functions_for_' + profile + ' [] = {'
    117     for func in sorted(function_names):
    118         print '   builtin_' + func + ','
    119     print '};'
    120 
    121 def write_profiles():
    122     profiles = get_profile_list()
    123     for (filename, profile) in profiles:
    124         write_profile(filename, profile)
    125 
    126 def get_profile_list():
    127     profile_files = []
    128     for extension in ['glsl', 'frag', 'vert']:
    129         path_glob = path.join(
    130             path.join(builtins_dir, 'profiles'), '*.' + extension)
    131         profile_files.extend(glob(path_glob))
    132     profiles = []
    133     for pfile in sorted(profile_files):
    134         profiles.append((pfile, path.basename(pfile).replace('.', '_')))
    135     return profiles
    136 
    137 if __name__ == "__main__":
    138     print """/* DO NOT MODIFY - automatically generated by generate_builtins.py */
    139 /*
    140  * Copyright  2010 Intel Corporation
    141  *
    142  * Permission is hereby granted, free of charge, to any person obtaining a
    143  * copy of this software and associated documentation files (the "Software"),
    144  * to deal in the Software without restriction, including without limitation
    145  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
    146  * and/or sell copies of the Software, and to permit persons to whom the
    147  * Software is furnished to do so, subject to the following conditions:
    148  *
    149  * The above copyright notice and this permission notice (including the next
    150  * paragraph) shall be included in all copies or substantial portions of the
    151  * Software.
    152  *
    153  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    154  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    155  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
    156  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    157  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    158  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    159  * DEALINGS IN THE SOFTWARE.
    160  */
    161 
    162 #include <stdio.h>
    163 #include "main/core.h" /* for struct gl_shader */
    164 #include "glsl_parser_extras.h"
    165 #include "ir_reader.h"
    166 #include "program.h"
    167 #include "ast.h"
    168 
    169 extern "C" struct gl_shader *
    170 _mesa_new_shader(struct gl_context *ctx, GLuint name, GLenum type);
    171 
    172 gl_shader *
    173 read_builtins(GLenum target, const char *protos, const char **functions, unsigned count)
    174 {
    175    struct gl_context fakeCtx;
    176    fakeCtx.API = API_OPENGL;
    177    fakeCtx.Const.GLSLVersion = 140;
    178    fakeCtx.Extensions.ARB_ES2_compatibility = true;
    179    fakeCtx.Const.ForceGLSLExtensionsWarn = false;
    180    gl_shader *sh = _mesa_new_shader(NULL, 0, target);
    181    struct _mesa_glsl_parse_state *st =
    182       new(sh) _mesa_glsl_parse_state(&fakeCtx, target, sh);
    183 
    184    st->language_version = 140;
    185    st->symbols->language_version = 140;
    186    st->ARB_texture_rectangle_enable = true;
    187    st->EXT_texture_array_enable = true;
    188    st->OES_EGL_image_external_enable = true;
    189    st->ARB_shader_bit_encoding_enable = true;
    190    _mesa_glsl_initialize_types(st);
    191 
    192    sh->ir = new(sh) exec_list;
    193    sh->symbols = st->symbols;
    194 
    195    /* Read the IR containing the prototypes */
    196    _mesa_glsl_read_ir(st, sh->ir, protos, true);
    197 
    198    /* Read ALL the function bodies, telling the IR reader not to scan for
    199     * prototypes (we've already created them).  The IR reader will skip any
    200     * signature that does not already exist as a prototype.
    201     */
    202    for (unsigned i = 0; i < count; i++) {
    203       _mesa_glsl_read_ir(st, sh->ir, functions[i], false);
    204 
    205       if (st->error) {
    206          printf("error reading builtin: %.35s ...\\n", functions[i]);
    207          printf("Info log:\\n%s\\n", st->info_log);
    208          ralloc_free(sh);
    209          return NULL;
    210       }
    211    }
    212 
    213    reparent_ir(sh->ir, sh);
    214    delete st;
    215 
    216    return sh;
    217 }
    218 """
    219 
    220     write_function_definitions()
    221     write_profiles()
    222 
    223     profiles = get_profile_list()
    224 
    225     print 'static gl_shader *builtin_profiles[%d];' % len(profiles)
    226 
    227     print """
    228 void *builtin_mem_ctx = NULL;
    229 
    230 void
    231 _mesa_glsl_release_functions(void)
    232 {
    233    ralloc_free(builtin_mem_ctx);
    234    builtin_mem_ctx = NULL;
    235    memset(builtin_profiles, 0, sizeof(builtin_profiles));
    236 }
    237 
    238 static void
    239 _mesa_read_profile(struct _mesa_glsl_parse_state *state,
    240                    int profile_index,
    241 		   const char *prototypes,
    242 		   const char **functions,
    243                    int count)
    244 {
    245    gl_shader *sh = builtin_profiles[profile_index];
    246 
    247    if (sh == NULL) {
    248       sh = read_builtins(GL_VERTEX_SHADER, prototypes, functions, count);
    249       ralloc_steal(builtin_mem_ctx, sh);
    250       builtin_profiles[profile_index] = sh;
    251    }
    252 
    253    state->builtins_to_link[state->num_builtins_to_link] = sh;
    254    state->num_builtins_to_link++;
    255 }
    256 
    257 void
    258 _mesa_glsl_initialize_functions(struct _mesa_glsl_parse_state *state)
    259 {
    260    /* If we've already initialized the built-ins, bail early. */
    261    if (state->num_builtins_to_link > 0)
    262       return;
    263 
    264    if (builtin_mem_ctx == NULL) {
    265       builtin_mem_ctx = ralloc_context(NULL); // "GLSL built-in functions"
    266       memset(&builtin_profiles, 0, sizeof(builtin_profiles));
    267    }
    268 """
    269 
    270     i = 0
    271     for (filename, profile) in profiles:
    272         if profile.endswith('_vert'):
    273             check = 'state->target == vertex_shader && '
    274         elif profile.endswith('_frag'):
    275             check = 'state->target == fragment_shader && '
    276         else:
    277             check = ''
    278 
    279         version = re.sub(r'_(glsl|vert|frag)$', '', profile)
    280         if version.isdigit():
    281             check += 'state->language_version == ' + version
    282         else: # an extension name
    283             check += 'state->' + version + '_enable'
    284 
    285         print '   if (' + check + ') {'
    286         print '      _mesa_read_profile(state, %d,' % i
    287         print '                         prototypes_for_' + profile + ','
    288         print '                         functions_for_' + profile + ','
    289         print '                         Elements(functions_for_' + profile + '));'
    290         print '   }'
    291         print
    292         i = i + 1
    293     print '}'
    294 
    295