summaryrefslogtreecommitdiff
path: root/misc/spirv_as.py
diff options
context:
space:
mode:
Diffstat (limited to 'misc/spirv_as.py')
-rw-r--r--misc/spirv_as.py119
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)