mesa/src/gallium/drivers/swr/rasterizer/codegen/gen_archrast.py

328 lines
11 KiB
Python

# Copyright (C) 2014-2016 Intel Corporation. All Rights Reserved.
#
# 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.
# Python source
import os
import sys
import re
from gen_common import *
def parse_event_fields(lines, idx, event_dict):
"""
Parses lines from a proto file that contain an event definition and stores it in event_dict
"""
fields = []
end_of_event = False
# record all fields in event definition.
# note: we don't check if there's a leading brace.
while not end_of_event and idx < len(lines):
line = lines[idx].rstrip()
idx += 1
# ex 1: uint32_t numSampleCLZExecuted; // number of sample_cl_z instructions executed
# ex 2: char reason[256]; // size of reason
match = re.match(r'^(\s*)([\w\*]+)(\s+)([\w]+)(\[\d+\])*;\s*(\/\/.*)*$', line)
# group 1 -
# group 2 type
# group 3 -
# group 4 name
# group 5 [array size]
# group 6 //comment
if match:
field = {
"type": match.group(2),
"name": match.group(4),
"size": int(match.group(5)[1:-1]) if match.group(5) else 1,
"desc": match.group(6)[2:].strip() if match.group(6) else "",
}
fields.append(field)
end_of_event = re.match(r'(\s*)};', line)
event_dict['fields'] = fields
event_dict['num_fields'] = len(fields)
return idx
def parse_enums(lines, idx, event_dict):
"""
Parses lines from a proto file that contain an enum definition and stores it in event_dict
"""
enum_names = []
end_of_enum = False
# record all enum values in enumeration
# note: we don't check if there's a leading brace.
while not end_of_enum and idx < len(lines):
line = lines[idx].rstrip()
idx += 1
preprocessor = re.search(r'#if|#endif', line)
if not preprocessor:
enum = re.match(r'(\s*)(\w+)(\s*)', line)
if enum:
enum_names.append(line)
end_of_enum = re.match(r'(\s*)};', line)
event_dict['names'] = enum_names
return idx
def parse_protos(files, verbose=False):
"""
Parses a proto file and returns a dictionary of event definitions
"""
# Protos structure:
#
# {
# "events": {
# "defs": { // dict of event definitions where keys are 'group_name::event_name"
# ...,
# "ApiStat::DrawInfoEvent": {
# "id": 3,
# "group": "ApiStat",
# "name": "DrawInfoEvent", // name of event without 'group_name::' prefix
# "desc": "",
# "fields": [
# {
# "type": "uint32_t",
# "name": "drawId",
# "size": 1,
# "desc": "",
# },
# ...
# ]
# },
# ...
# },
# "groups": { // dict of groups with lists of event keys
# "ApiStat": [
# "ApiStat::DispatchEvent",
# "ApiStat::DrawInfoEvent",
# ...
# ],
# "Framework": [
# "Framework::ThreadStartApiEvent",
# "Framework::ThreadStartWorkerEvent",
# ...
# ],
# ...
# },
# "map": { // map of event ids to match archrast output to event key
# "1": "Framework::ThreadStartApiEvent",
# "2": "Framework::ThreadStartWorkerEvent",
# "3": "ApiStat::DrawInfoEvent",
# ...
# }
# },
# "enums": { ... } // enums follow similar defs, map (groups?) structure
# }
protos = {
'events': {
'defs': {}, # event dictionary containing events with their fields
'map': {}, # dictionary to map event ids to event names
'groups': {} # event keys stored by groups
},
'enums': {
'defs': {},
'map': {}
}
}
event_id = 0
enum_id = 0
if type(files) is not list:
files = [files]
for filename in files:
if verbose:
print("Parsing proto file: %s" % os.path.normpath(filename))
with open(filename, 'r') as f:
lines = f.readlines()
in_brief = False
brief = []
idx = 0
while idx < len(lines):
line = lines[idx].strip()
idx += 1
# If currently processing a brief, keep processing or change state
if in_brief:
match = re.match(r'^\s*\/\/\/\s*(.*)$', line) # i.e. "/// more event desc..."
if match:
brief.append(match.group(1).strip())
continue
else:
in_brief = False
# Match event/enum brief
match = re.match(r'^\s*\/\/\/\s*@(brief|breif)\s*(.*)$', line) # i.e. "///@brief My event desc..."
if match:
in_brief = True
brief.append(match.group(2).strip())
continue
# Match event definition
match = re.match(r'event(\s*)(((\w*)::){0,1}(\w+))', line) # i.e. "event SWTag::CounterEvent"
if match:
event_id += 1
# Parse event attributes
event_key = match.group(2) # i.e. SWTag::CounterEvent
event_group = match.group(4) if match.group(4) else "" # i.e. SWTag
event_name = match.group(5) # i.e. CounterEvent
# Define event attributes
event = {
'id': event_id,
'group': event_group,
'name': event_name,
'desc': ' '.join(brief)
}
# Add period at end of event desc if necessary
if event["desc"] and event["desc"][-1] != '.':
event["desc"] += '.'
# Reset brief
brief = []
# Now add event fields
idx = parse_event_fields(lines, idx, event)
# Register event and mapping
protos['events']['defs'][event_key] = event
protos['events']['map'][event_id] = event_key
continue
# Match enum definition
match = re.match(r'enum(\s*)(\w+)', line)
if match:
enum_id += 1
# Parse enum attributes
enum_name = match.group(2)
# Define enum attr
enum = {
'name': enum_name,
'desc': ' '.join(brief)
}
# Add period at end of event desc if necessary
if enum["desc"] and enum["desc"][-1] != '.':
enum["desc"] += '.'
# Reset brief
brief = []
# Now add enum fields
idx = parse_enums(lines, idx, enum)
# Register enum and mapping
protos['enums']['defs'][enum_name] = enum
protos['enums']['map'][enum_id] = enum_name
continue
# Sort and group events
event_groups = protos['events']['groups']
for key in sorted(protos['events']['defs']):
group = protos['events']['defs'][key]['group']
if group not in event_groups:
event_groups[group] = []
event_groups[group].append(key)
return protos
def main():
# Parse args...
parser = ArgumentParser()
parser.add_argument("--proto", "-p", dest="protos", nargs='+', help="Path to all proto file(s) to process. Accepts one or more paths (i.e. events.proto and events_private.proto)", required=True)
parser.add_argument("--output-dir", help="Output dir (defaults to ./codegen). Will create folder if it does not exist.", required=False, default="codegen")
parser.add_argument("--verbose", "-v", help="Verbose", action="store_true")
args = parser.parse_args()
if not os.path.exists(args.output_dir):
MakeDir(args.output_dir)
for f in args.protos:
if not os.path.exists(f):
print('Error: Could not find proto file %s' % f, file=sys.stderr)
return 1
# Parse each proto file and add to protos container
protos = parse_protos(args.protos, args.verbose)
files = [
["gen_ar_event.hpp", ""],
["gen_ar_event.cpp", ""],
["gen_ar_eventhandler.hpp", "gen_ar_event.hpp"],
["gen_ar_eventhandlerfile.hpp", "gen_ar_eventhandler.hpp"]
]
rval = 0
try:
# Delete existing files
for f in files:
filename = f[0]
output_fullpath = os.path.join(args.output_dir, filename)
if os.path.exists(output_fullpath):
if args.verbose:
print("Deleting existing file: %s" % output_fullpath)
os.remove(output_fullpath)
# Generate files from templates
print("Generating c++ from proto files...")
for f in files:
filename = f[0]
event_header = f[1]
curdir = os.path.dirname(os.path.abspath(__file__))
template_file = os.path.join(curdir, 'templates', filename)
output_fullpath = os.path.join(args.output_dir, filename)
if args.verbose:
print("Generating: %s" % output_fullpath)
MakoTemplateWriter.to_file(template_file, output_fullpath,
cmdline=sys.argv,
filename=filename,
protos=protos,
event_header=event_header)
except Exception as e:
print(e)
rval = 1
return rval
if __name__ == '__main__':
sys.exit(main())