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