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