1#!/usr/bin/env python3
2#
3# Copyright (C) 2016 Google, Inc.
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#     http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17"""Compile GLSL to SPIR-V.
18
19Depends on glslangValidator.
20"""
21
22import os
23import sys
24import subprocess
25import struct
26import re
27
28SPIRV_MAGIC = 0x07230203
29COLUMNS = 4
30INDENT = 4
31
32in_filename = sys.argv[1]
33out_filename = sys.argv[2] if len(sys.argv) > 2 else None
34validator = sys.argv[3] if len(sys.argv) > 3 else \
35        "../../../glslang/build/install/bin/glslangValidator"
36
37def identifierize(s):
38    # translate invalid chars
39    s = re.sub("[^0-9a-zA-Z_]", "_", s)
40    # translate leading digits
41    return re.sub("^[^a-zA-Z_]+", "_", s)
42
43def compile_glsl(filename, tmpfile):
44    # invoke glslangValidator
45    try:
46        args = [validator, "-V", "-H", "-o", tmpfile, filename]
47        output = subprocess.check_output(args, universal_newlines=True)
48    except subprocess.CalledProcessError as e:
49        print(e.output, file=sys.stderr)
50        exit(1)
51
52    # read the temp file into a list of SPIR-V words
53    words = []
54    with open(tmpfile, "rb") as f:
55        data = f.read()
56        assert(len(data) and len(data) % 4 == 0)
57
58        # determine endianness
59        fmt = ("<" if data[0] == (SPIRV_MAGIC & 0xff) else ">") + "I"
60        for i in range(0, len(data), 4):
61            words.append(struct.unpack(fmt, data[i:(i + 4)])[0])
62
63        assert(words[0] == SPIRV_MAGIC)
64
65
66    # remove temp file
67    os.remove(tmpfile)
68
69    return (words, output.rstrip())
70
71base = os.path.basename(in_filename)
72words, comments = compile_glsl(in_filename, base + ".tmp")
73
74literals = []
75for i in range(0, len(words), COLUMNS):
76    columns = ["0x%08x" % word for word in words[i:(i + COLUMNS)]]
77    literals.append(" " * INDENT + ", ".join(columns) + ",")
78
79header = """#include <stdint.h>
80
81#if 0
82%s
83#endif
84
85static const uint32_t %s[%d] = {
86%s
87};
88""" % (comments, identifierize(base), len(words), "\n".join(literals))
89
90if out_filename:
91    with open(out_filename, "w") as f:
92        print(header, end="", file=f)
93else:
94        print(header, end="")
95