#!/usr/bin/python
# -*- coding: utf-8 -*-
import re
from glob import glob
from os import path
from subprocess import Popen, PIPE
# Local module: generator for texture lookup builtins
from texture_builtins import generate_texture_functions
builtins_dir = path.join(path.dirname(path.abspath(__file__)), "..")
# 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'), '*')):
with open(filename) as f:
fs[path.basename(filename)] = f.read()
# Return a dictionary containing all builtin definitions (even generated)
def get_builtin_definitions():
fs = {}
generate_texture_functions(fs)
read_ir_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):
compiler_path = path.join(path.join(builtins_dir, '..'), 'glsl_compiler')
command = [compiler_path, '--dump-lir'] + args
p = Popen(command, 1, stdout=PIPE, shell=False)
output = p.communicate()[0]
# 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')
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
# Kill any global variable declarations. We don't want them.
kill_globals = re.compile(r'^\(declare.*\n', re.MULTILINE);
proto_ir = kill_globals.sub('', proto_ir)
# Kill pointer addresses. They're not necessary in prototypes and just
# clutter the diff output.
proto_ir = re.sub(r'@0x[0-9a-f]+', '', proto_ir);
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():
profiles = []
for pfile in sorted(glob(path.join(path.join(builtins_dir, 'profiles'), '*'))):
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/shaderobj.h" /* for struct gl_shader */
#include "glsl_parser_extras.h"
#include "ir_reader.h"
#include "program.h"
#include "ast.h"
gl_shader *
read_builtins(void * mem_ctx, GLenum target, const char *protos, const char **functions, unsigned count)
{
struct gl_context fakeCtx;
fakeCtx.API = API_OPENGL;
gl_shader *sh = _mesa_new_shader(mem_ctx, 0, target);
struct _mesa_glsl_parse_state *st =
new(sh) _mesa_glsl_parse_state(&fakeCtx, target, sh);
st->language_version = 130;
st->symbols->language_version = 130;
st->ARB_texture_rectangle_enable = true;
st->EXT_texture_array_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);
_mesa_delete_shader(NULL, 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)
{
hieralloc_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,
exec_list *instructions,
int profile_index,
const char *prototypes,
const char **functions,
int count)
{
gl_shader *sh = builtin_profiles[profile_index];
if (sh == NULL) {
sh = read_builtins(state, GL_VERTEX_SHADER, prototypes, functions, count);
hieralloc_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(exec_list *instructions,
struct _mesa_glsl_parse_state *state)
{
if (builtin_mem_ctx == NULL) {
builtin_mem_ctx = hieralloc_init("GLSL built-in functions");
memset(&builtin_profiles, 0, sizeof(builtin_profiles));
}
state->num_builtins_to_link = 0;
"""
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 && '
version = re.sub(r'_(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, instructions, %d,' % i
print ' prototypes_for_' + profile + ','
print ' functions_for_' + profile + ','
print ' Elements(functions_for_' + profile + '));'
print ' }'
print
i = i + 1
print '}'