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