generate_builtins.py revision 6355ae2b80a01b1d58824ffeae0c638d917519c0
1#!/usr/bin/python
2# -*- coding: UTF-8 -*-
3
4import re
5from glob import glob
6from os import path
7from subprocess import Popen, PIPE
8
9# Local module: generator for texture lookup builtins
10from texture_builtins import generate_texture_functions
11
12builtins_dir = path.join(path.dirname(path.abspath(__file__)), "..")
13
14# Read the files in builtins/ir/*...add them to the supplied dictionary.
15def read_ir_files(fs):
16    for filename in glob(path.join(path.join(builtins_dir, 'ir'), '*')):
17        with open(filename) as f:
18            fs[path.basename(filename)] = f.read()
19
20# Return a dictionary containing all builtin definitions (even generated)
21def get_builtin_definitions():
22    fs = {}
23    generate_texture_functions(fs)
24    read_ir_files(fs)
25    return fs
26
27def stringify(s):
28    t = s.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n"\n   "')
29    return '   "' + t + '"\n'
30
31def write_function_definitions():
32    fs = get_builtin_definitions()
33    for k, v in sorted(fs.iteritems()):
34        print 'static const char *builtin_' + k + ' ='
35        print stringify(v), ';'
36
37def run_compiler(args):
38    compiler_path = path.join(path.join(builtins_dir, '..'), 'glsl_compiler')
39    command = [compiler_path, '--dump-lir'] + args
40    p = Popen(command, 1, stdout=PIPE, shell=False)
41    output = p.communicate()[0]
42
43    # Clean up output a bit by killing whitespace before a closing paren.
44    kill_paren_whitespace = re.compile(r'[ \n]*\)', re.MULTILINE);
45    output = kill_paren_whitespace.sub(')', output);
46
47    # Also toss any duplicate newlines
48    output = output.replace('\n\n', '\n')
49
50    return (output, p.returncode)
51
52def write_profile(filename, profile):
53    (proto_ir, returncode) = run_compiler([filename])
54
55    if returncode != 0:
56        print '#error builtins profile', profile, 'failed to compile'
57        return
58
59    # Kill any global variable declarations.  We don't want them.
60    kill_globals = re.compile(r'^\(declare.*\n', re.MULTILINE);
61    proto_ir = kill_globals.sub('', proto_ir)
62
63    # Kill pointer addresses.  They're not necessary in prototypes and just
64    # clutter the diff output.
65    proto_ir = re.sub(r'@0x[0-9a-f]+', '', proto_ir);
66
67    print 'static const char *prototypes_for_' + profile + ' ='
68    print stringify(proto_ir), ';'
69
70    # Print a table of all the functions (not signatures) referenced.
71    # This is done so we can avoid bothering with a hash table in the C++ code.
72
73    function_names = set()
74    for func in re.finditer(r'\(function (.+)\n', proto_ir):
75        function_names.add(func.group(1))
76
77    print 'static const char *functions_for_' + profile + ' [] = {'
78    for func in sorted(function_names):
79        print '   builtin_' + func + ','
80    print '};'
81
82def write_profiles():
83    profiles = get_profile_list()
84    for (filename, profile) in profiles:
85        write_profile(filename, profile)
86
87def get_profile_list():
88    profiles = []
89    for pfile in sorted(glob(path.join(path.join(builtins_dir, 'profiles'), '*'))):
90        profiles.append((pfile, path.basename(pfile).replace('.', '_')))
91    return profiles
92
93if __name__ == "__main__":
94    print """/* DO NOT MODIFY - automatically generated by generate_builtins.py */
95/*
96 * Copyright © 2010 Intel Corporation
97 *
98 * Permission is hereby granted, free of charge, to any person obtaining a
99 * copy of this software and associated documentation files (the "Software"),
100 * to deal in the Software without restriction, including without limitation
101 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
102 * and/or sell copies of the Software, and to permit persons to whom the
103 * Software is furnished to do so, subject to the following conditions:
104 *
105 * The above copyright notice and this permission notice (including the next
106 * paragraph) shall be included in all copies or substantial portions of the
107 * Software.
108 *
109 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
110 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
111 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
112 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
113 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
114 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
115 * DEALINGS IN THE SOFTWARE.
116 */
117
118#include <stdio.h>
119#include "main/compiler.h"
120#include "glsl_parser_extras.h"
121#include "ir_reader.h"
122#include "program.h"
123#include "ast.h"
124
125extern "C" struct gl_shader *
126_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type);
127
128gl_shader *
129read_builtins(GLenum target, const char *protos, const char **functions, unsigned count)
130{
131   gl_shader *sh = _mesa_new_shader(NULL, 0, target);
132   struct _mesa_glsl_parse_state *st =
133      new(sh) _mesa_glsl_parse_state(NULL, target, sh);
134
135   st->language_version = 130;
136   st->ARB_texture_rectangle_enable = true;
137   st->EXT_texture_array_enable = true;
138   _mesa_glsl_initialize_types(st);
139
140   sh->ir = new(sh) exec_list;
141   sh->symbols = st->symbols;
142
143   /* Read the IR containing the prototypes */
144   _mesa_glsl_read_ir(st, sh->ir, protos, true);
145
146   /* Read ALL the function bodies, telling the IR reader not to scan for
147    * prototypes (we've already created them).  The IR reader will skip any
148    * signature that does not already exist as a prototype.
149    */
150   for (unsigned i = 0; i < count; i++) {
151      _mesa_glsl_read_ir(st, sh->ir, functions[i], false);
152
153      if (st->error) {
154         printf("error reading builtin: %.35s ...\\n", functions[i]);
155         talloc_free(sh);
156         return NULL;
157      }
158   }
159
160   reparent_ir(sh->ir, sh);
161   delete st;
162
163   return sh;
164}
165"""
166
167    write_function_definitions()
168    write_profiles()
169
170    print """
171void *builtin_mem_ctx = NULL;
172
173void
174_mesa_glsl_release_functions(void)
175{
176    talloc_free(builtin_mem_ctx);
177}
178
179void
180_mesa_glsl_initialize_functions(exec_list *instructions,
181                                struct _mesa_glsl_parse_state *state)
182{
183   if (builtin_mem_ctx == NULL)
184      builtin_mem_ctx = talloc_init("GLSL built-in functions");
185
186   state->num_builtins_to_link = 0;
187"""
188
189    profiles = get_profile_list()
190    for (filename, profile) in profiles:
191        if profile.endswith('_vert'):
192            check = 'state->target == vertex_shader && '
193        elif profile.endswith('_frag'):
194            check = 'state->target == fragment_shader && '
195
196        version = re.sub(r'_(vert|frag)$', '', profile)
197        if version.isdigit():
198            check += 'state->language_version == ' + version
199        else: # an extension name
200            check += 'state->' + version + '_enable'
201
202        print '   if (' + check + ') {'
203        print '      static gl_shader *sh = NULL;'
204        print '      if (sh == NULL) {'
205        print '         sh = read_builtins(GL_VERTEX_SHADER,'
206        print '                            prototypes_for_' + profile + ','
207        print '                            functions_for_' + profile + ','
208        print '                            Elements(functions_for_' + profile,
209        print '));'
210        print '         talloc_steal(builtin_mem_ctx, sh);'
211        print '      }'
212        print
213        print '      import_prototypes(sh->ir, instructions, state->symbols,'
214        print '                        state);'
215        print '      state->builtins_to_link[state->num_builtins_to_link] = sh;'
216        print '      state->num_builtins_to_link++;'
217        print '   }'
218        print
219    print '}'
220
221