# coding=utf-8 # Copyright 2014 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. """ Generate C source code from Khronos XML. """ from __future__ import ( absolute_import, division, print_function, unicode_literals ) import argparse import os.path import re import sys import functools from collections import namedtuple import six import mako.runtime import mako.template PIGLIT_TOP_DIR = os.path.join(os.path.dirname(__file__), '..', '..') sys.path.append(PIGLIT_TOP_DIR) import registry.gl # pylint: disable=import-error debug = False def log_debug(msg): if debug: prog_name = os.path.basename(sys.argv[0]) print('debug: {0}: {1}'.format(prog_name, msg), file=sys.stderr) def main(): global debug argparser = argparse.ArgumentParser() argparser.add_argument('-o', '--out-dir', required=True) argparser.add_argument('-d', '--debug', action='store_true', default=False) args = argparser.parse_args() debug = args.debug registry.gl.debug = debug gl_registry = registry.gl.parse() DispatchCode.emit(args.out_dir, gl_registry) EnumCode.emit(args.out_dir, gl_registry) class DispatchCode(object): H_TEMPLATE = 'piglit-dispatch-gen.h.mako' C_TEMPLATE = 'piglit-dispatch-gen.c.mako' Api = namedtuple('DispatchApi', ('name', 'base_version_int', 'c_piglit_token')) APIS = { 'gl': Api('gl', 10, 'PIGLIT_DISPATCH_GL'), 'gles1': Api('gles1', 11, 'PIGLIT_DISPATCH_ES1'), 'gles2': Api('gles2', 20, 'PIGLIT_DISPATCH_ES2'), } APIS['glcore'] = APIS['gl'] assert set(APIS.keys()) | set(['glsc2']) == set(registry.gl.VALID_APIS) @classmethod def emit(cls, out_dir, gl_registry): assert isinstance(gl_registry, registry.gl.Registry) context_vars = dict(dispatch=cls, gl_registry=gl_registry) render_template(cls.H_TEMPLATE, out_dir, **context_vars) render_template(cls.C_TEMPLATE, out_dir, **context_vars) def render_template(filename, out_dir, **context_vars): assert filename.endswith('.mako') template_filepath = os.path.join(os.path.dirname(__file__), filename) out_filepath = os.path.join(out_dir, os.path.splitext(filename)[0]) warning = 'DO NOT EDIT! Script {0!r} generated this file from {1!r}' warning = warning.format(os.path.basename(__file__), filename) fake_alignment = re.compile(r'\.*\n\.+', flags=re.MULTILINE) fake_tab = re.compile(r'>-------') def fake_whitespace(proto_text): if debug: print('fake whitespace: before: {0!r}'.format(proto_text)) if six.PY2: # the unicode function was removed in python3, this will raise a # pylint error, but not in python2 # pylint: disable=undefined-variable text = unicode(proto_text) elif six.PY3: text = proto_text text = fake_alignment.sub('', text) text = fake_tab.sub('\t', text) if debug: print('fake whitespace: after: {0!r}'.format(text)) return text with open(out_filepath, 'w') as out_file: template = mako.template.Template( filename=template_filepath, strict_undefined=True) ctx = mako.runtime.Context( buffer=out_file, warning=warning, fake_whitespace=fake_whitespace, **context_vars) template.render_context(ctx) class EnumCode(object): C_TEMPLATE = 'piglit-util-gl-enum-gen.c.mako' @classmethod def emit(cls, out_dir, gl_registry): assert isinstance(gl_registry, registry.gl.Registry) enums = cls.get_enums_in_default_namespace(gl_registry) unique_enums = cls.get_unique_enums(enums) enums_by_name = cls.get_enums_by_name(enums) memory_barrier = cls.get_enums_in_memory_barrier_group(gl_registry) render_template( cls.C_TEMPLATE, out_dir, gl_registry=gl_registry, sorted_unique_enums_in_default_namespace=unique_enums, sorted_enums_by_name=enums_by_name, sorted_by_name_memory_barrier_enums=memory_barrier) @classmethod def get_enums_in_default_namespace(cls, gl_registry): enums = [] for enum_group in gl_registry.enum_groups: if enum_group.type == 'default_namespace': for enum in enum_group.enums: enums.append(enum) return enums @classmethod def get_enums_in_memory_barrier_group(cls, gl_registry): enums = [] for enum_group in gl_registry.enum_groups: if enum_group.name == 'MemoryBarrierMask': if enum_group.type == 'bitmask': for enum in enum_group.enums: enums.append(enum) return cls.get_enums_by_name(enums) @classmethod def get_unique_enums(cls, enums): def append_enum_if_new_value(enum_list, enum): if enum_list[-1].num_value < enum.num_value: enum_list.append(enum) return enum_list enums = sorted(enums) enums = functools.reduce(append_enum_if_new_value, enums[1:], [enums[0]]) return enums @classmethod def get_enums_by_name(cls, enums): enums = sorted(enums, key=lambda enum: enum.name) return enums if __name__ == '__main__': main()