forked from mirrors/gecko-dev
		
	 6c3c26c3f7
			
		
	
	
		6c3c26c3f7
		
	
	
	
	
		
			
			MozReview-Commit-ID: BFnq9JpWZxq --HG-- extra : rebase_source : d56375d1ff0f183f95e0565851191190fe41e34b
		
			
				
	
	
		
			171 lines
		
	
	
	
		
			4.8 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable file
		
	
	
	
	
			
		
		
	
	
			171 lines
		
	
	
	
		
			4.8 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable file
		
	
	
	
	
| # This Source Code Form is subject to the terms of the Mozilla Public
 | |
| # License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
| # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 | |
| import argparse
 | |
| import codecs
 | |
| import locale
 | |
| import os
 | |
| import re
 | |
| import subprocess
 | |
| import sys
 | |
| import tempfile
 | |
| import yaml
 | |
| import buildconfig
 | |
| 
 | |
| 
 | |
| def shell_main():
 | |
|     parser = argparse.ArgumentParser()
 | |
|     parser.add_argument('-o', '--output', type=str, required=True,
 | |
|                         help='Output file')
 | |
|     parser.add_argument('manifest', type=str,
 | |
|                         help='Manifest source file')
 | |
|     args = parser.parse_args()
 | |
| 
 | |
|     with open(args.output, 'w') as out_file:
 | |
|         process_manifest(out_file, args.manifest)
 | |
| 
 | |
| 
 | |
| def main(output_fp, input_filename):
 | |
|     return process_manifest(output_fp, input_filename)
 | |
| 
 | |
| 
 | |
| HEADER = """// AUTOGENERATED - DO NOT EDIT
 | |
| namespace mozilla {
 | |
| namespace layers {
 | |
| 
 | |
| struct ShaderBytes { const void* mData; size_t mLength; };
 | |
| """
 | |
| FOOTER = """
 | |
| } // namespace layers
 | |
| } // namespace mozilla"""
 | |
| 
 | |
| 
 | |
| def process_manifest(output_fp, manifest_filename):
 | |
|     with codecs.open(manifest_filename, 'r', 'UTF-8') as in_fp:
 | |
|         manifest = yaml.safe_load(in_fp)
 | |
|     shader_folder, _ = os.path.split(manifest_filename)
 | |
| 
 | |
|     output_fp.write(HEADER)
 | |
| 
 | |
|     deps = set()
 | |
|     for block in manifest:
 | |
|         if 'type' not in block:
 | |
|             raise Exception("Expected 'type' key with shader mode")
 | |
|         if 'file' not in block:
 | |
|             raise Exception("Expected 'file' key with shader file")
 | |
|         if 'shaders' not in block:
 | |
|             raise Exception("Expected 'shaders' key with shader name list")
 | |
| 
 | |
|         shader_file = os.path.join(shader_folder, block['file'])
 | |
|         deps.add(shader_file)
 | |
| 
 | |
|         shader_model = block['type']
 | |
|         for shader_name in block['shaders']:
 | |
|             new_deps = run_fxc(
 | |
|                 shader_model=shader_model,
 | |
|                 shader_file=shader_file,
 | |
|                 shader_name=shader_name,
 | |
|                 output_fp=output_fp)
 | |
|             deps |= new_deps
 | |
| 
 | |
|     output_fp.write(FOOTER)
 | |
|     return deps
 | |
| 
 | |
| 
 | |
| def run_fxc(shader_model,
 | |
|             shader_file,
 | |
|             shader_name,
 | |
|             output_fp):
 | |
|     fxc_location = buildconfig.substs['FXC']
 | |
| 
 | |
|     argv = [
 | |
|         fxc_location,
 | |
|         '-nologo',
 | |
|         '-T{0}'.format(shader_model),
 | |
|         shader_file,
 | |
|         '-E{0}'.format(shader_name),
 | |
|         '-Vn{0}'.format(shader_name),
 | |
|         '-Vi',
 | |
|     ]
 | |
|     if 'Linux' in buildconfig.substs['HOST_OS_ARCH']:
 | |
|         argv.insert(0, buildconfig.substs['WINE'])
 | |
|     if shader_model.startswith('vs_'):
 | |
|         argv += ['-DVERTEX_SHADER']
 | |
|     elif shader_model.startswith('ps_'):
 | |
|         argv += ['-DPIXEL_SHADER']
 | |
| 
 | |
|     deps = None
 | |
|     with ScopedTempFilename() as temp_filename:
 | |
|         argv += ['-Fh{0}'.format(temp_filename)]
 | |
| 
 | |
|         sys.stdout.write('{0}\n'.format(' '.join(argv)))
 | |
|         proc_stdout = subprocess.check_output(argv)
 | |
|         proc_stdout = decode_console_text(sys.stdout, proc_stdout)
 | |
|         deps = find_dependencies(proc_stdout)
 | |
|         assert 'fxc2' in fxc_location or len(deps) > 0
 | |
| 
 | |
|         with open(temp_filename, 'r') as temp_fp:
 | |
|             output_fp.write(temp_fp.read())
 | |
| 
 | |
|     output_fp.write("ShaderBytes s{0} = {{ {0}, sizeof({0}) }};\n".format(
 | |
|         shader_name))
 | |
|     return deps
 | |
| 
 | |
| 
 | |
| def find_dependencies(fxc_output):
 | |
|     # Dependencies look like this:
 | |
|     #   Resolved to [<path>]
 | |
|     #
 | |
|     # Microsoft likes to change output strings based on the user's language, so
 | |
|     # instead of pattern matching on that string, we take everything in between
 | |
|     # brackets. We filter out potentially bogus strings later.
 | |
|     deps = set()
 | |
|     for line in fxc_output.split('\n'):
 | |
|         m = re.search(r"\[([^\]]+)\]", line)
 | |
|         if m is None:
 | |
|             continue
 | |
|         dep_path = m.group(1)
 | |
|         dep_path = os.path.normpath(dep_path)
 | |
|         if os.path.isfile(dep_path):
 | |
|             deps.add(dep_path)
 | |
|     return deps
 | |
| 
 | |
| # Python reads the raw bytes from stdout, so we need to try our best to
 | |
| # capture that as a valid Python string.
 | |
| 
 | |
| 
 | |
| def decode_console_text(pipe, text):
 | |
|     try:
 | |
|         if pipe.encoding:
 | |
|             return text.decode(pipe.encoding, 'replace')
 | |
|     except Exception:
 | |
|         pass
 | |
|     try:
 | |
|         return text.decode(locale.getpreferredencoding(), 'replace')
 | |
|     except Exception:
 | |
|         return text.decode('utf8', 'replace')
 | |
| 
 | |
| # Allocate a temporary file name and delete it when done. We need an extra
 | |
| # wrapper for this since TemporaryNamedFile holds the file open.
 | |
| 
 | |
| 
 | |
| class ScopedTempFilename(object):
 | |
|     def __init__(self):
 | |
|         self.name = None
 | |
| 
 | |
|     def __enter__(self):
 | |
|         with tempfile.NamedTemporaryFile(delete=False) as tmp:
 | |
|             self.name = tmp.name
 | |
|             return self.name
 | |
| 
 | |
|     def __exit__(self, type, value, traceback):
 | |
|         if not self.name:
 | |
|             return
 | |
|         try:
 | |
|             os.unlink(self.name)
 | |
|         except Exception:
 | |
|             pass
 | |
| 
 | |
| 
 | |
| if __name__ == '__main__':
 | |
|     shell_main()
 |