| #!/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 '}' |
| |