diff options
Diffstat (limited to 'misc/spirv_as.py')
-rw-r--r-- | misc/spirv_as.py | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/misc/spirv_as.py b/misc/spirv_as.py new file mode 100644 index 0000000..5e31157 --- /dev/null +++ b/misc/spirv_as.py @@ -0,0 +1,119 @@ +#! /usr/bin/env python3 + +import argparse +import io +import os +import re +import shutil +import struct +import subprocess +import sys +import tempfile +from textwrap import dedent + +class ShaderCompileError(RuntimeError): + def __init__(self, *args): + super(ShaderCompileError, self).__init__(*args) + +class Shader: + def __init__(self, in_file): + self.dwords = None + self.in_file = in_file + self.name = os.path.splitext(os.path.basename(in_file))[0] + + def __run_spirv_as(self): + with subprocess.Popen([spirv_as] + + ['-o', '-', self.in_file], + stdout = subprocess.PIPE, + stderr = subprocess.PIPE) as proc: + + out, err = proc.communicate(timeout=30) + + if proc.returncode != 0: + # Unfortunately, glslang dumps errors to standard out. + # However, since we don't really want to count on that, + # we'll grab the output of both + message = out.decode('utf-8') + '\n' + err.decode('utf-8') + raise ShaderCompileError(message.strip()) + + return out + + def compile(self): + def dwords(f): + while True: + dword_str = f.read(4) + if not dword_str: + return + assert len(dword_str) == 4 + yield struct.unpack('I', dword_str)[0] + + spirv = self.__run_spirv_as() + self.dwords = list(dwords(io.BytesIO(spirv))) + + def dump_c_code(self, f): + f.write('static const uint32_t __{0}_spir_v_src[] = {{'.format(self.name)) + line_start = 0 + while line_start < len(self.dwords): + f.write('\n ') + for i in range(line_start, min(line_start + 6, len(self.dwords))): + f.write(' 0x{:08x},'.format(self.dwords[i])) + line_start += 6 + f.write('\n};\n\n') + + f.write(dedent("""\ + #define {0}_info \ + .spirvSize = sizeof(__{0}_spir_v_src), \ + .pSpirv = __{0}_spir_v_src + """.format(self.name))) + +def open_file(name, mode): + if name == '-': + if mode == 'w': + return sys.stdout + elif mode == 'r': + return sys.stdin + else: + assert False + else: + return open(name, mode) + +def parse_args(): + description = dedent("""\ + This program assembles a SPIR-V shader and emits a header with the + resulting binary that can be included by a test. + + If '-' is passed as the input file or output file, stdin or stdout + will be used instead of a file on disc.""") + + p = argparse.ArgumentParser( + description=description, + formatter_class=argparse.RawDescriptionHelpFormatter) + p.add_argument('-o', '--outfile', default='-', + help='Output to the given file (default: stdout).') + p.add_argument('--with-spirv-as', metavar='PATH', + default='spirv-as', + dest='spirv_as', + help='Full path to the spirv-as assembler.') + p.add_argument('infile', metavar='INFILE') + + return p.parse_args() + + +args = parse_args() +infname = args.infile +outfname = args.outfile +spirv_as = args.spirv_as + +shader = Shader(infname) +shader.compile() + +with open_file(outfname, 'w') as outfile: + outfile.write(dedent("""\ + /* ========================== DO NOT EDIT! ========================== + * This file is autogenerated by spirv_as.py. + */ + + #include <stdint.h> + + """)) + shader.dump_c_code(outfile) |