#!/usr/bin/python # -*- coding: utf-8 -*- from __future__ import with_statement import re import sys from glob import glob from os import path from subprocess import Popen, PIPE from sys import argv # Local module: generator for texture lookup builtins from texture_builtins import generate_texture_functions builtins_dir = path.join(path.dirname(path.abspath(__file__)), "..") # Get the path to the standalone GLSL compiler if len(argv) != 2: print "Usage:", argv[0], "<path to compiler>" sys.exit(1) compiler = argv[1] # Read the files in builtins/ir/*...add them to the supplied dictionary. def read_ir_files(fs): for filename in glob(path.join(path.join(builtins_dir, 'ir'), '*.ir')): function_name = path.basename(filename).split('.')[0] with open(filename) as f: fs[function_name] = f.read() def read_glsl_files(fs): for filename in glob(path.join(path.join(builtins_dir, 'glsl'), '*.glsl')): function_name = path.basename(filename).split('.')[0] (output, returncode) = run_compiler([filename]) if (returncode): sys.stderr.write("Failed to compile builtin: " + filename + "\n") sys.stderr.write("Result:\n") sys.stderr.write(output) else: fs[function_name] = output; # Return a dictionary containing all builtin definitions (even generated) def get_builtin_definitions(): fs = {} generate_texture_functions(fs) read_ir_files(fs) read_glsl_files(fs) return fs def stringify(s): # Work around MSVC's 65535 byte limit by outputting an array of characters # rather than actual string literals. if len(s) >= 65535: #t = "/* Warning: length " + repr(len(s)) + " too large */\n" t = "" for c in re.sub('\s\s+', ' ', s): if c == '\n': t += '\n' else: t += "'" + c + "'," return '{' + t[:-1] + '}' t = s.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n"\n "') return ' "' + t + '"\n' def write_function_definitions(): fs = get_builtin_definitions() for k, v in sorted(fs.iteritems()): print 'static const char builtin_' + k + '[] =' print stringify(v), ';' def run_compiler(args): command = [compiler, '--dump-hir'] + args p = Popen(command, 1, stdout=PIPE, shell=False) output = p.communicate()[0] if (p.returncode): sys.stderr.write("Failed to compile builtins with command:\n") for arg in command: sys.stderr.write(arg + " ") sys.stderr.write("\n") sys.stderr.write("Result:\n") sys.stderr.write(output) # Clean up output a bit by killing whitespace before a closing paren. kill_paren_whitespace = re.compile(r'[ \n]*\)', re.MULTILINE) output = kill_paren_whitespace.sub(')', output) # Also toss any duplicate newlines output = output.replace('\n\n', '\n') # Kill any global variable declarations. We don't want them. kill_globals = re.compile(r'^\(declare.*\n', re.MULTILINE) output = kill_globals.sub('', output) return (output, p.returncode) def write_profile(filename, profile): (proto_ir, returncode) = run_compiler([filename]) if returncode != 0: print '#error builtins profile', profile, 'failed to compile' return print 'static const char prototypes_for_' + profile + '[] =' print stringify(proto_ir), ';' # Print a table of all the functions (not signatures) referenced. # This is done so we can avoid bothering with a hash table in the C++ code. function_names = set() for func in re.finditer(r'\(function (.+)\n', proto_ir): function_names.add(func.group(1)) print 'static const char *functions_for_' + profile + ' [] = {' for func in sorted(function_names): print ' builtin_' + func + ',' print '};' def write_profiles(): profiles = get_profile_list() for (filename, profile) in profiles: write_profile(filename, profile) def get_profile_list(): profile_files = [] for extension in ['glsl', 'frag', 'vert']: path_glob = path.join( path.join(builtins_dir, 'profiles'), '*.' + extension) profile_files.extend(glob(path_glob)) profiles = [] for pfile in sorted(profile_files): profiles.append((pfile, path.basename(pfile).replace('.', '_'))) return profiles if __name__ == "__main__": print """/* DO NOT MODIFY - automatically generated by generate_builtins.py */ /* * Copyright © 2010 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include <stdio.h> #include "main/core.h" /* for struct gl_shader */ #include "glsl_parser_extras.h" #include "ir_reader.h" #include "program.h" #include "ast.h" extern "C" struct gl_shader * _mesa_new_shader(struct gl_context *ctx, GLuint name, GLenum type); gl_shader * read_builtins(GLenum target, const char *protos, const char **functions, unsigned count) { struct gl_context fakeCtx; fakeCtx.API = API_OPENGL; fakeCtx.Const.GLSLVersion = 140; fakeCtx.Extensions.ARB_ES2_compatibility = true; fakeCtx.Const.ForceGLSLExtensionsWarn = false; gl_shader *sh = _mesa_new_shader(NULL, 0, target); struct _mesa_glsl_parse_state *st = new(sh) _mesa_glsl_parse_state(&fakeCtx, target, sh); st->language_version = 140; st->symbols->language_version = 140; st->ARB_texture_rectangle_enable = true; st->EXT_texture_array_enable = true; st->OES_EGL_image_external_enable = true; st->ARB_shader_bit_encoding_enable = true; _mesa_glsl_initialize_types(st); sh->ir = new(sh) exec_list; sh->symbols = st->symbols; /* Read the IR containing the prototypes */ _mesa_glsl_read_ir(st, sh->ir, protos, true); /* Read ALL the function bodies, telling the IR reader not to scan for * prototypes (we've already created them). The IR reader will skip any * signature that does not already exist as a prototype. */ for (unsigned i = 0; i < count; i++) { _mesa_glsl_read_ir(st, sh->ir, functions[i], false); if (st->error) { printf("error reading builtin: %.35s ...\\n", functions[i]); printf("Info log:\\n%s\\n", st->info_log); ralloc_free(sh); return NULL; } } reparent_ir(sh->ir, sh); delete st; return sh; } """ write_function_definitions() write_profiles() profiles = get_profile_list() print 'static gl_shader *builtin_profiles[%d];' % len(profiles) print """ void *builtin_mem_ctx = NULL; void _mesa_glsl_release_functions(void) { ralloc_free(builtin_mem_ctx); builtin_mem_ctx = NULL; memset(builtin_profiles, 0, sizeof(builtin_profiles)); } static void _mesa_read_profile(struct _mesa_glsl_parse_state *state, int profile_index, const char *prototypes, const char **functions, int count) { gl_shader *sh = builtin_profiles[profile_index]; if (sh == NULL) { sh = read_builtins(GL_VERTEX_SHADER, prototypes, functions, count); ralloc_steal(builtin_mem_ctx, sh); builtin_profiles[profile_index] = sh; } state->builtins_to_link[state->num_builtins_to_link] = sh; state->num_builtins_to_link++; } void _mesa_glsl_initialize_functions(struct _mesa_glsl_parse_state *state) { /* If we've already initialized the built-ins, bail early. */ if (state->num_builtins_to_link > 0) return; if (builtin_mem_ctx == NULL) { builtin_mem_ctx = ralloc_context(NULL); // "GLSL built-in functions" memset(&builtin_profiles, 0, sizeof(builtin_profiles)); } """ i = 0 for (filename, profile) in profiles: if profile.endswith('_vert'): check = 'state->target == vertex_shader && ' elif profile.endswith('_frag'): check = 'state->target == fragment_shader && ' else: check = '' version = re.sub(r'_(glsl|vert|frag)$', '', profile) if version.isdigit(): check += 'state->language_version == ' + version else: # an extension name check += 'state->' + version + '_enable' print ' if (' + check + ') {' print ' _mesa_read_profile(state, %d,' % i print ' prototypes_for_' + profile + ',' print ' functions_for_' + profile + ',' print ' Elements(functions_for_' + profile + '));' print ' }' print i = i + 1 print '}'