glsl: add builtins for geometry shaders.
[mesa.git] / src / glsl / builtins / tools / generate_builtins.py
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', 'geom']:
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_COMPAT;
177 fakeCtx.Const.GLSLVersion = 150;
178 fakeCtx.Extensions.ARB_ES2_compatibility = true;
179 fakeCtx.Extensions.ARB_ES3_compatibility = true;
180 fakeCtx.Const.ForceGLSLExtensionsWarn = false;
181 gl_shader *sh = _mesa_new_shader(NULL, 0, target);
182 struct _mesa_glsl_parse_state *st =
183 new(sh) _mesa_glsl_parse_state(&fakeCtx, target, sh);
184
185 st->language_version = 150;
186 st->symbols->separate_function_namespace = false;
187 st->ARB_texture_rectangle_enable = true;
188 st->EXT_texture_array_enable = true;
189 st->OES_EGL_image_external_enable = true;
190 st->ARB_shader_bit_encoding_enable = true;
191 st->ARB_texture_cube_map_array_enable = true;
192 st->ARB_shading_language_packing_enable = true;
193 st->ARB_texture_multisample_enable = true;
194 st->ARB_texture_query_lod_enable = true;
195 st->ARB_gpu_shader5_enable = true;
196 _mesa_glsl_initialize_types(st);
197
198 sh->ir = new(sh) exec_list;
199 sh->symbols = st->symbols;
200
201 /* Read the IR containing the prototypes */
202 _mesa_glsl_read_ir(st, sh->ir, protos, true);
203
204 /* Read ALL the function bodies, telling the IR reader not to scan for
205 * prototypes (we've already created them). The IR reader will skip any
206 * signature that does not already exist as a prototype.
207 */
208 for (unsigned i = 0; i < count; i++) {
209 _mesa_glsl_read_ir(st, sh->ir, functions[i], false);
210
211 if (st->error) {
212 printf("error reading builtin: %.35s ...\\n", functions[i]);
213 printf("Info log:\\n%s\\n", st->info_log);
214 ralloc_free(sh);
215 return NULL;
216 }
217 }
218
219 reparent_ir(sh->ir, sh);
220 delete st;
221
222 return sh;
223 }
224 """
225
226 write_function_definitions()
227 write_profiles()
228
229 profiles = get_profile_list()
230
231 print 'static gl_shader *builtin_profiles[%d];' % len(profiles)
232
233 print """
234 static void *builtin_mem_ctx = NULL;
235
236 void
237 _mesa_glsl_release_functions(void)
238 {
239 ralloc_free(builtin_mem_ctx);
240 builtin_mem_ctx = NULL;
241 memset(builtin_profiles, 0, sizeof(builtin_profiles));
242 }
243
244 static void
245 _mesa_read_profile(struct _mesa_glsl_parse_state *state,
246 int profile_index,
247 const char *prototypes,
248 const char **functions,
249 int count)
250 {
251 gl_shader *sh = builtin_profiles[profile_index];
252
253 if (sh == NULL) {
254 sh = read_builtins(GL_VERTEX_SHADER, prototypes, functions, count);
255 ralloc_steal(builtin_mem_ctx, sh);
256 builtin_profiles[profile_index] = sh;
257 }
258
259 state->builtins_to_link[state->num_builtins_to_link] = sh;
260 state->num_builtins_to_link++;
261 }
262
263 void
264 _mesa_glsl_initialize_functions(struct _mesa_glsl_parse_state *state)
265 {
266 /* If we've already initialized the built-ins, bail early. */
267 if (state->num_builtins_to_link > 0)
268 return;
269
270 if (builtin_mem_ctx == NULL) {
271 builtin_mem_ctx = ralloc_context(NULL); // "GLSL built-in functions"
272 memset(&builtin_profiles, 0, sizeof(builtin_profiles));
273 }
274 """
275
276 i = 0
277 for (filename, profile) in profiles:
278 if profile.endswith('_vert'):
279 check = 'state->target == vertex_shader && '
280 elif profile.endswith('_frag'):
281 check = 'state->target == fragment_shader && '
282 elif profile.endswith('_geom'):
283 check = 'state->target == geometry_shader && '
284 else:
285 check = ''
286
287 version = re.sub(r'_(glsl|vert|frag|geom)$', '', profile)
288 if version[0].isdigit():
289 is_es = version.endswith('es')
290 if is_es:
291 version = version[:-2]
292 check += 'state->language_version == ' + version
293 check += ' && {0}state->es_shader'.format('' if is_es else '!')
294 else: # an extension name
295 check += 'state->' + version + '_enable'
296
297 print ' if (' + check + ') {'
298 print ' _mesa_read_profile(state, %d,' % i
299 print ' prototypes_for_' + profile + ','
300 print ' functions_for_' + profile + ','
301 print ' Elements(functions_for_' + profile + '));'
302 print ' }'
303 print
304 i = i + 1
305 print '}'
306