Add support for multiple subprograms

This commit is contained in:
gsemaj 2022-08-11 11:53:38 -04:00
parent d0e67d55c9
commit 3791e889c8
3 changed files with 55 additions and 36 deletions

View File

@ -6,6 +6,5 @@ Tools for converting d3d9 shader assembly to HLSL/Cg.
## Known issues ## Known issues
- Only vertex shaders with profile `vs_1_1` are supported - Only vertex shaders with profile `vs_1_1` are supported
- No fragment shaders are supported yet - Only fragment shaders with profile `ps_2_0` are supported
- Only one subprogram in a subshader will be converted (for now)
- Only a limited set of instructions (those used by FF and Unity 2.6) are supported - Only a limited set of instructions (those used by FF and Unity 2.6) are supported

View File

@ -115,7 +115,6 @@ fragment_func = """float4 frag(v2f pdat) {{
def process_header(prog): def process_header(prog):
keywords = [] keywords = []
header = []
loctab = {} loctab = {}
locdecl = [] locdecl = []
binds = [] binds = []
@ -192,19 +191,10 @@ def process_header(prog):
del prog[i] del prog[i]
i = i - 1 i = i - 1
i = i + 1 i = i + 1
if len(binds) > 0:
header.append("BindChannels {")
for b in binds:
header.append(f"\t{b}")
header.append("}")
if lighting:
header.append("Lighting On")
# print(loctab) # print(loctab)
return (keywords, header, loctab, locdecl) return (keywords, loctab, locdecl, binds, lighting)
def resolve_args(args, loctab, consts): def resolve_args(args, loctab, consts):
for a in range(0, len(args)): for a in range(0, len(args)):
@ -306,28 +296,52 @@ def process_asm(asm, loctab):
return (shadertype, translated) return (shadertype, translated)
def disassemble(text): def disassemble(blocks):
asm = text.split('\n')[1:-1] shaders = {}
(keywords, header, loctab, locdecl) = process_header(asm) keywords = set()
(shadertype, disasm) = process_asm(asm, loctab) locdecl = set()
binds = set()
lighting = False
for block in blocks:
asm = block.split('\n')[1:-1]
(kw, ltab, ldecl, bds, light) = process_header(asm)
keywords.update(kw)
locdecl.update(ldecl)
binds.update(bds)
lighting |= light
(shadertype, disasm) = process_asm(asm, ltab)
shaders[shadertype] = disasm
text = ""
if len(binds) > 0:
text += "BindChannels {\n"
for b in binds:
text += f"\t{b}\n"
text += "}\n"
text = "\n".join(header) + "\n" if len(header) > 0 else "" if lighting:
text += "Lighting On\n"
text += cg_header text += cg_header
if keywords: if len(keywords) > 0:
text += "#pragma multi_compile " + " ".join(keywords) text += "#pragma multi_compile " + " ".join(keywords)
if shadertype == "vertex": if "vertex" in shaders:
text += "#pragma vertex vert\n" text += "#pragma vertex vert\n"
if shadertype == "fragment": if "fragment" in shaders:
text += "#pragma fragment frag\n" text += "#pragma fragment frag\n"
text += "\n" text += "\n"
text += struct_a2v + "\n" if "vertex" in shaders:
text += struct_a2v + "\n"
text += struct_v2f + "\n" text += struct_v2f + "\n"
text += struct_f2a + "\n" if "fragment" in shaders:
text += struct_f2a + "\n"
text += "\n".join(locdecl) + "\n" text += "\n".join(locdecl) + "\n"
if shadertype == "vertex": if "vertex" in shaders:
text += vertex_func.format("\t" + "\n\t".join(disasm)) text += "\n" + vertex_func.format("\t" + "\n\t".join(shaders["vertex"]))
if shadertype == "fragment": if "fragment" in shaders:
text += fragment_func.format("\t" + "\n\t".join(disasm)) text += "\n" + fragment_func.format("\t" + "\n\t".join(shaders["fragment"]))
text += cg_footer text += cg_footer
return text return text
@ -337,5 +351,5 @@ if __name__ == "__main__":
else: else:
with open(sys.argv[1], "r") as fi: with open(sys.argv[1], "r") as fi:
buf = fi.read() buf = fi.read()
disasm = disassemble(buf) disasm = disassemble(buf.split('~'))
print(disasm) print(disasm)

View File

@ -27,18 +27,24 @@ def find_closing_bracket(block, i):
raise ValueError(f"Block at {i} has no closing bracket") raise ValueError(f"Block at {i} has no closing bracket")
def process_program(prog): def process_program(prog):
# print("processing:\n" + prog)
subprogs = []
subprog_index = prog.find("SubProgram \"d3d9") subprog_index = prog.find("SubProgram \"d3d9")
if subprog_index == -1: while subprog_index > -1:
raise ValueError(f"Program has no d3d9 subprogram") subprog_end_index = find_closing_bracket(prog, subprog_index)
subprog_end_index = find_closing_bracket(prog, subprog_index) subprog = prog[subprog_index:subprog_end_index+1]
subprog = prog[subprog_index:subprog_end_index+1] subprogs.append(subprog)
processed = disassemble(subprog) + "\n" prog = prog[subprog_end_index+1:]
subprog_index = prog.find("SubProgram \"d3d9")
if len(subprogs) < 1:
raise ValueError(f"Program has no d3d9 subprograms")
processed = disassemble(subprogs) + "\n"
return indent(processed) return indent(processed)
def process_shader(shader): def process_shader(shader):
buf = shader buf = shader
processed = '' processed = ''
program_index = buf.find('Program') program_index = buf.find("Program \"\"")
while program_index > -1: while program_index > -1:
processed = processed + buf[:program_index] processed = processed + buf[:program_index]
buf = buf[program_index:] buf = buf[program_index:]
@ -46,11 +52,11 @@ def process_shader(shader):
if not line: if not line:
raise ValueError(f"Program at {program_index} has no #LINE marker") raise ValueError(f"Program at {program_index} has no #LINE marker")
end_index = line.end() + 1 end_index = line.end() + 1
program_section = buf[program_index:end_index+1] program_section = buf[:end_index+1]
processed = processed + process_program(program_section) processed = processed + process_program(program_section)
buf = buf[end_index+1:] buf = buf[end_index+1:]
program_index = buf.find('Program') program_index = buf.find("Program \"\"")
processed = processed + buf processed = processed + buf
return processed return processed