diff --git a/compiler.py b/compiler.py index c5fd0b3..bd3bde8 100644 --- a/compiler.py +++ b/compiler.py @@ -12,8 +12,10 @@ from typing import List, Dict from binding_manager import BindingManager from code_generator import CodeGenerator from compiler_cmd import make_cmd +from exe_finder import dxc_path +from global_vars import global_vars from shader_parser import ShaderParser -from shader_types import ShaderInfo, TargetFormat +from shader_types import ShaderInfo, TargetFormat, ShaderStage class SDL3GPUSlangCompiler: @@ -47,23 +49,62 @@ class SDL3GPUSlangCompiler: try: # 编译着色器 - cmd = make_cmd(tmp_path, target, shader_info.stage, shader_info.entry_point, output_path) + if target == TargetFormat.DXIL: + cmd = make_cmd(tmp_path, TargetFormat.HLSL_DX12, shader_info.stage, shader_info.entry_point, output_path) + else: + cmd = make_cmd(tmp_path, target, shader_info.stage, shader_info.entry_point, output_path) + print(f"Compiling shader with command: {' '.join(cmd)}") + shader_file = output_path subprocess.run(cmd, check=True) print(f"Shader compiled successfully") + # 如果目标是DXIL,则需要签名 + if global_vars.target == TargetFormat.DXIL: + with tempfile.NamedTemporaryFile(mode='w', suffix='.cso', delete=False, encoding='utf8') as tmp: + signed_shader = tmp.name + self._compile_dxil(shader_info, shader_file, signed_shader) + shader_file = signed_shader + # 生成绑定信息 - binding_info = self.binding_manager.generate_binding_info(shader_info, target, output_path) + binding_info = self.binding_manager.generate_binding_info(shader_info, target, shader_file) return binding_info finally: # 清理临时文件 os.unlink(tmp_path) + os.unlink(signed_shader) os.unlink(output_path) - def generate_binding_functions(self, binding_infos: List[Dict], output_path: str): """生成C/C++绑定函数""" - self.code_generator.generate_binding_functions(binding_infos, output_path) \ No newline at end of file + self.code_generator.generate_binding_functions(binding_infos, output_path) + def _compile_dxil(self, shader_info: ShaderInfo, input_file: str, output_file: str): + """编译DXIL着色器""" + # 根据stage选择不同的-T参数 + if shader_info.stage == ShaderStage.VERTEX: + t = 'vs_6_6' + elif shader_info.stage == ShaderStage.FRAGMENT: + t = 'ps_6_6' + elif shader_info.stage == ShaderStage.COMPUTE: + t = 'cs_6_6' + else: + raise ValueError(f"Unsupported shader stage: {shader_info.stage}") + + dxc_cmd = [ + dxc_path, + '-T', t, + '-E', shader_info.entry_point, + '-Fo', output_file, + input_file + ] + + result = subprocess.run(dxc_cmd, check=True) + if result.stdout: + print(f"Stdout: {result.stdout}") + if result.stderr is None: + print(f"Signed shader compiled successfully") + else: + raise RuntimeError(f"Failed to compile DXIL shader: {result.stderr.decode('utf-8')}") \ No newline at end of file diff --git a/compiler_cmd.py b/compiler_cmd.py index ee70113..c7e38d5 100644 --- a/compiler_cmd.py +++ b/compiler_cmd.py @@ -2,10 +2,9 @@ """ SDL3_GPU Slang Compiler - Command Generation """ +from exe_finder import slangc_path from global_vars import global_vars from shader_types import TargetFormat, ShaderStage -from slangc_finder import slangc_path - def make_cmd(source_file: str, target: TargetFormat, stage: ShaderStage, entry_point: str, output_path: str): """生成编译命令""" @@ -13,7 +12,9 @@ def make_cmd(source_file: str, target: TargetFormat, stage: ShaderStage, entry_p TargetFormat.SPIRV: 'spirv', TargetFormat.DXIL: 'dxil', TargetFormat.DXBC: 'dxbc', - TargetFormat.MSL: 'metal' + TargetFormat.MSL: 'metal', + TargetFormat.HLSL_DX12: 'hlsl', + TargetFormat.HLSL_DX11: 'hlsl', }[target] stage_flag = { @@ -35,9 +36,9 @@ def make_cmd(source_file: str, target: TargetFormat, stage: ShaderStage, entry_p for include_path in global_vars.include_dirs: cmd.extend(['-I', include_path]) - if target == TargetFormat.DXIL: - cmd.extend(['-profile', 'sm_6_0']) - elif target == TargetFormat.DXBC: + if target == TargetFormat.DXIL or target == TargetFormat.HLSL_DX12: + cmd.extend(['-profile', 'sm_6_6']) + elif target == TargetFormat.DXBC or target == TargetFormat.HLSL_DX11: cmd.extend(['-profile', 'sm_5_1']) return cmd diff --git a/slangc_finder.py b/exe_finder.py similarity index 83% rename from slangc_finder.py rename to exe_finder.py index 35b430e..131564c 100644 --- a/slangc_finder.py +++ b/exe_finder.py @@ -90,3 +90,18 @@ compiler.slangc_path = r'C:\\path\\to\\slangc.exe' """) slangc_path = SlangcFinder.find_slangc() + +# 如果是windows系统,检查DXC编译器 +if os.name == 'nt': + # 查找dxcapsviewer.exe路径, 避免查找dxc时找到Vulkan SDK的dxc.exe + dxcapsviewer_path = shutil.which('dxcapsviewer.exe') + if dxcapsviewer_path: + # dxc.exe一般与dxcapsviewer.exe在同一目录 + dxc_path = os.path.join(os.path.dirname(dxcapsviewer_path), 'dxc.exe') + # 检查dxc.exe是否存在 + if not os.path.isfile(dxc_path): + print("Warning: dxc.exe not found in the same directory as dxcapsviewer.exe.") + dxc_path = None + else: + # 如果没有找到dxcapsviewer.exe,尝试直接查找dxc.exe + dxc_path = shutil.which('dxc.exe') diff --git a/main.py b/main.py index c5a9f20..98c2bf6 100644 --- a/main.py +++ b/main.py @@ -30,7 +30,10 @@ def main(): global_vars.source_file_name = os.path.splitext(os.path.basename(input_path))[0] global_vars.source_path = os.path.dirname(input_path) global_vars.output_dir = os.path.abspath(args.output_dir) - global_vars.target = target = TargetFormat(args.target) + global_vars.target = TargetFormat(args.target) + # if global_vars.target == TargetFormat.DXIL: + # global_vars.target = TargetFormat.DXBC + # print("Warning: DXIL target is not supported, using DXBC instead.") # 仅保留路径部分 include_dirs = [ @@ -54,7 +57,7 @@ def main(): for name, shader_info in shaders.items(): print(f"**Compiling** {name}...") - binding_info = compiler.compile_shader(shader_info, target) + binding_info = compiler.compile_shader(shader_info, global_vars.target) binding_infos.append(binding_info) binding_output_file_pathname = os.path.abspath(args.output_dir) diff --git a/shader_types.py b/shader_types.py index b5dc1a1..f89e7de 100644 --- a/shader_types.py +++ b/shader_types.py @@ -26,6 +26,8 @@ class TargetFormat(Enum): DXIL = "dxil" DXBC = "dxbc" MSL = "msl" + HLSL_DX12 = "hlsl" + HLSL_DX11 = "hlsl" @dataclass class Resource: