Files
mirage_slang/compiler.py
2025-06-11 14:32:56 +08:00

110 lines
4.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
SDL3_GPU Slang Compiler - Main Compiler
主编译器类,整合所有功能模块
"""
import os
import subprocess
import tempfile
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, ShaderStage
class SDL3GPUSlangCompiler:
def __init__(self):
self.parser = ShaderParser()
self.binding_manager = BindingManager()
self.code_generator = CodeGenerator()
def parse_slang_shader(self) -> Dict[str, ShaderInfo]:
"""解析Slang着色器源码提取资源信息"""
return self.parser.parse_slang_shader()
def compile_shader(self, shader_info: ShaderInfo, target: TargetFormat) -> tuple[str, dict]:
"""编译着色器并返回二进制路径和绑定信息"""
output_path = tempfile.mktemp()
# 根据目标格式分配绑定点
if target == TargetFormat.SPIRV:
self.binding_manager.assign_bindings_spirv(shader_info)
elif target in [TargetFormat.DXIL, TargetFormat.DXBC]:
self.binding_manager.assign_bindings_dxil(shader_info)
elif target == TargetFormat.MSL:
self.binding_manager.assign_bindings_msl(shader_info)
# 生成带绑定信息的着色器代码
modified_source = self.binding_manager.inject_bindings(shader_info, target)
# 写入临时文件
with tempfile.NamedTemporaryFile(mode='w', suffix='.slang', delete=False, encoding='utf8') as tmp:
tmp.write(modified_source)
tmp_path = tmp.name
try:
# 编译着色器
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, 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)
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')}")