5 glsl_scraper.py [options] file
7 This program scrapes a C file for any instance of the GLSL_VK_SHADER macro,
8 grabs the GLSL source code, compiles it to SPIR-V. The resulting SPIR-V
9 code is written to another C file as an array of 32-bit words.
11 If '-' is passed as the input file or output file, stdin or stdout will be
12 used instead of a file on disc.
15 -o outfile Output to the given file (default: stdout)
16 --with-glslang=PATH Full path to the glslangValidator program"""
19 import os
, sys
, re
, cStringIO
, tempfile
, subprocess
, struct
, shutil
22 def __init__(self
, stage
):
23 self
.stream
= cStringIO
.StringIO()
26 if self
.stage
== 'VERTEX':
28 elif self
.stage
== 'TESS_CONTROL':
30 elif self
.stage
== 'TESS_EVALUATION':
32 elif self
.stage
== 'GEOMETRY':
34 elif self
.stage
== 'FRAGMENT':
36 elif self
.stage
== 'COMPUTE':
41 def add_text(self
, s
):
44 def finish_text(self
, line
):
47 def glsl_source(self
):
48 return self
.stream
.getvalue()
51 # We can assume if we got here that we have a temp directory and that
52 # we're currently living in it.
53 glsl_fname
= 'shader{0}.{1}'.format(self
.line
, self
.ext
)
54 spirv_fname
= self
.ext
+ '.spv'
56 glsl_file
= open(glsl_fname
, 'w')
57 glsl_file
.write('#version 420 core\n')
58 glsl_file
.write(self
.glsl_source())
61 out
= open('glslang.out', 'wb')
62 err
= subprocess
.call([glslang
, '-V', glsl_fname
], stdout
=out
)
64 out
= open('glslang.out', 'r')
65 sys
.stderr
.write(out
.read())
74 assert len(dword_str
) == 4
75 yield struct
.unpack('I', dword_str
)[0]
77 spirv_file
= open(spirv_fname
, 'rb')
78 self
.dwords
= list(dwords(spirv_file
))
82 os
.remove(spirv_fname
)
84 def dump_c_code(self
, f
, glsl_only
= False):
86 var_prefix
= '_glsl_helpers_shader{0}'.format(self
.line
)
88 # First dump the GLSL source as strings
89 f
.write('static const char {0}_glsl_src[] ='.format(var_prefix
))
90 f
.write('\n"#version 330\\n"')
91 for line
in self
.glsl_source().splitlines():
94 f
.write('\n"{0}\\n"'.format(line
))
100 # Now dump the SPIR-V source
101 f
.write('static const uint32_t {0}_spir_v_src[] = {{'.format(var_prefix
))
103 while line_start
< len(self
.dwords
):
105 for i
in range(line_start
, min(line_start
+ 6, len(self
.dwords
))):
106 f
.write(' 0x{:08x},'.format(self
.dwords
[i
]))
110 token_exp
= re
.compile(r
'(GLSL_VK_SHADER|\(|\)|,)')
113 def __init__(self
, f
):
125 m
= token_exp
.search(line
, pos
)
128 leftover
+= line
[pos
:m
.start()]
138 leftover
+= line
[pos
:]
141 self
.line_number
+= 1
146 self
.token_iter
= tokenize(self
.infile
)
148 def handle_shader_src(self
):
150 for t
in self
.token_iter
:
158 self
.current_shader
.add_text(t
)
160 def handle_macro(self
):
161 t
= self
.token_iter
.next()
163 t
= self
.token_iter
.next()
164 t
= self
.token_iter
.next()
167 stage
= self
.token_iter
.next().strip()
169 t
= self
.token_iter
.next()
172 self
.current_shader
= Shader(stage
)
173 self
.handle_shader_src()
174 self
.current_shader
.finish_text(self
.line_number
)
176 self
.shaders
.append(self
.current_shader
)
177 self
.current_shader
= None
180 for t
in self
.token_iter
:
181 if t
== 'GLSL_VK_SHADER':
184 def open_file(name
, mode
):
193 return open(name
, mode
)
197 glslang
= 'glslangValidator'
201 while arg_idx
< len(sys
.argv
):
202 if sys
.argv
[arg_idx
] == '-h':
204 elif sys
.argv
[arg_idx
] == '-o':
206 outfname
= sys
.argv
[arg_idx
]
207 elif sys
.argv
[arg_idx
].startswith('--with-glslang='):
208 glslang
= sys
.argv
[arg_idx
][len('--with-glslang='):]
209 elif sys
.argv
[arg_idx
] == '--glsl-only':
212 infname
= sys
.argv
[arg_idx
]
216 if arg_idx
< len(sys
.argv
) - 1 or not infname
or not outfname
:
219 with
open_file(infname
, 'r') as infile
:
220 parser
= Parser(infile
)
224 # glslangValidator has an absolutely *insane* interface. We pretty much
225 # have to run in a temporary directory. Sad day.
226 current_dir
= os
.getcwd()
227 tmpdir
= tempfile
.mkdtemp('glsl_scraper')
232 for shader
in parser
.shaders
:
235 os
.chdir(current_dir
)
237 shutil
.rmtree(tmpdir
)
239 with
open_file(outfname
, 'w') as outfile
:
241 /* =========================== DO NOT EDIT! ===========================
242 * This file is autogenerated by glsl_scraper.py.
247 #define _GLSL_SRC_VAR2(_line) _glsl_helpers_shader ## _line ## _glsl_src
248 #define _GLSL_SRC_VAR(_line) _GLSL_SRC_VAR2(_line)
250 #define GLSL_VK_SHADER(device, stage, ...) ({ \\
251 VkShader __shader; \\
252 VkShaderCreateInfo __shader_create_info = { \\
253 .sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO, \\
254 .codeSize = sizeof(_GLSL_SRC_VAR(__LINE__)), \\
255 .pCode = _GLSL_SRC_VAR(__LINE__), \\
257 vkCreateShader((VkDevice) device, &__shader_create_info, &__shader); \\
262 for shader
in parser
.shaders
:
263 shader
.dump_c_code(outfile
, glsl_only
)