165 lines
6.1 KiB
Python
Executable File
165 lines
6.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
#####################################################################
|
|
# Copyright (c) 2020 The Khronos Group Inc. All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
#####################################################################
|
|
|
|
"""Assembles the SPIR-V assembly files used by spirv_new into binaries,
|
|
and validates them using spirv-val. Either run this from the parent
|
|
of the spirv_asm directory, or pass the --source-dir and --output-dir
|
|
options to specify the locations of the assembly files and the
|
|
binaries to be generated.
|
|
"""
|
|
|
|
import argparse
|
|
import glob
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
from textwrap import wrap
|
|
|
|
|
|
def fatal(message):
|
|
"""Print an error message and exit with a non-zero status, to
|
|
indicate failure.
|
|
"""
|
|
print(message)
|
|
sys.exit(1)
|
|
|
|
|
|
def assemble_spirv(asm_dir, bin_dir, spirv_as, verbose):
|
|
"""Assemble SPIR-V source into binaries."""
|
|
|
|
if not os.path.exists(bin_dir):
|
|
os.makedirs(bin_dir)
|
|
|
|
assembly_failures = False
|
|
|
|
for asm_file_path in glob.glob(os.path.join(asm_dir, '*.spvasm*')):
|
|
asm_file = os.path.basename(asm_file_path)
|
|
if os.path.isfile(asm_file_path):
|
|
if verbose:
|
|
print(' Assembling {}'.format(asm_file))
|
|
|
|
asm_file_root, asm_file_ext = os.path.splitext(asm_file)
|
|
bin_file = asm_file_root + asm_file_ext.replace('asm', '')
|
|
bin_file_path = os.path.join(bin_dir, bin_file)
|
|
|
|
command = '"{}" --target-env spv1.0 "{}" -o "{}"'.format(
|
|
spirv_as, asm_file_path, bin_file_path)
|
|
if subprocess.call(command, shell=True) != 0:
|
|
assembly_failures = True
|
|
print('ERROR: Failure assembling {}: '
|
|
'see above output.'.format(
|
|
asm_file))
|
|
print()
|
|
|
|
if assembly_failures:
|
|
fatal('\n'.join(wrap(
|
|
'ERROR: Assembly failure(s) occurred. See above for error '
|
|
'messages from the assembler, if any.')))
|
|
|
|
|
|
def validate_spirv(bin_dir, spirv_val, verbose):
|
|
"""Validates SPIR-V binaries. Ignores known failures."""
|
|
|
|
validation_failures = False
|
|
|
|
for bin_file_path in glob.glob(os.path.join(bin_dir, '*.spv*')):
|
|
bin_file = os.path.basename(bin_file_path)
|
|
if os.path.isfile(bin_file_path):
|
|
if verbose:
|
|
print(' Validating {}'.format(bin_file))
|
|
|
|
command = '"{}" "{}"'.format(
|
|
spirv_val, bin_file_path)
|
|
if subprocess.call(command, shell=True) != 0:
|
|
print('ERROR: Failure validating {}: '
|
|
'see above output.'.format(
|
|
bin_file))
|
|
validation_failures = True
|
|
print()
|
|
|
|
if validation_failures:
|
|
fatal('ERROR: Validation failure(s) found. '
|
|
'See above for validation output.')
|
|
else:
|
|
print('All SPIR-V binaries validated successfully.')
|
|
|
|
|
|
def parse_args():
|
|
"""Parse the command-line arguments."""
|
|
|
|
argparse_kwargs = (
|
|
{'allow_abbrev': False} if sys.version_info >= (3, 5) else {})
|
|
argparse_kwargs['description'] = (
|
|
'''Assembles the SPIR-V assembly files used by spirv_new into
|
|
binaries, and validates them using spirv-val. Either run this
|
|
from the parent of the spirv_asm directory, or pass the
|
|
--source-dir and --output-dir options to specify the locations
|
|
the assembly files and the binaries to be generated.
|
|
''')
|
|
parser = argparse.ArgumentParser(**argparse_kwargs)
|
|
parser.add_argument('-s', '--source-dir', metavar='DIR',
|
|
default='spirv_asm',
|
|
help='''specifies the directory containing SPIR-V
|
|
assembly files''')
|
|
parser.add_argument('-o', '--output-dir', metavar='DIR',
|
|
default='spirv_bin',
|
|
help='''specifies the directory in which to
|
|
output SPIR-V binary files''')
|
|
parser.add_argument('-a', '--assembler', metavar='PROGRAM',
|
|
default='spirv-as',
|
|
help='''specifies the program to use for assembly
|
|
of SPIR-V, defaults to spirv-as''')
|
|
parser.add_argument('-l', '--validator', metavar='PROGRAM',
|
|
default='spirv-val',
|
|
help='''specifies the program to use for validation
|
|
of SPIR-V, defaults to spirv-val''')
|
|
parser.add_argument('-k', '--skip-validation', action='store_true',
|
|
default=False,
|
|
help='skips validation of the genareted SPIR-V')
|
|
parser.add_argument('-v', '--verbose', action='store_true', default=False,
|
|
help='''enable verbose output (i.e. prints the
|
|
name of each SPIR-V assembly file or
|
|
binary as it is assembled or validated)
|
|
''')
|
|
return parser.parse_args()
|
|
|
|
|
|
def main():
|
|
"""Main function. Assembles and validates SPIR-V."""
|
|
|
|
args = parse_args()
|
|
|
|
print('Assembling SPIR-V source into binaries...')
|
|
assemble_spirv(args.source_dir, args.output_dir, args.assembler,
|
|
args.verbose)
|
|
print('Finished assembling SPIR-V binaries.')
|
|
print()
|
|
|
|
if args.skip_validation:
|
|
print('Skipping validation of SPIR-V binaries as requested.')
|
|
else:
|
|
print('Validating SPIR-V binaries...')
|
|
validate_spirv(args.output_dir, args.validator, args.verbose)
|
|
print()
|
|
|
|
print('Done.')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|