From 99c80c9c7bf8d7b6298f8722434dea9f16aa50ce Mon Sep 17 00:00:00 2001 From: CakeLancelot Date: Tue, 13 Feb 2024 01:40:07 -0600 Subject: [PATCH 1/4] dx2cg: Allow usage as Python module e.g. from dx2cg.swapper import process_shader cg_shader = process_shader(text) --- dx2cg/__init__.py | 0 dx2cg/main.py | 2 +- dx2cg/swapper.py | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 dx2cg/__init__.py diff --git a/dx2cg/__init__.py b/dx2cg/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/dx2cg/main.py b/dx2cg/main.py index 79e7884..41b0341 100644 --- a/dx2cg/main.py +++ b/dx2cg/main.py @@ -3,7 +3,7 @@ import os import sys -from swapper import process +from .swapper import process def process_file(filename, suffix): dot = filename.rfind(".") diff --git a/dx2cg/swapper.py b/dx2cg/swapper.py index 89e63d5..0dfbd1c 100644 --- a/dx2cg/swapper.py +++ b/dx2cg/swapper.py @@ -5,7 +5,7 @@ import re import sys -from disassembler import disassemble +from .disassembler import disassemble tabs = 3 def indent(block): From 06869164a1ca1e82c49ca0ee1194b7f138208ec6 Mon Sep 17 00:00:00 2001 From: CakeLancelot Date: Tue, 13 Feb 2024 03:12:19 -0600 Subject: [PATCH 2/4] dx2cg: Implement mov_sat instruction Basically just mov but clamp the result. https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx9-graphics-reference-asm-ps-instructions-modifiers-ps-2-0#saturate --- dx2cg/disassembler.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dx2cg/disassembler.py b/dx2cg/disassembler.py index b3fc2a9..d3c1556 100644 --- a/dx2cg/disassembler.py +++ b/dx2cg/disassembler.py @@ -41,6 +41,7 @@ decls = { ops = { "mov": "{0} = {1};", + "mov_sat": "{0} = clamp({1}, 0.0, 1.0)", "add": "{0} = {1} + {2};", "mul": "{0} = {1} * {2};", "mad": "{0} = {1} * {2} + {3};", From d5b58d96da44967367dedb2b469f26fd45ce88cf Mon Sep 17 00:00:00 2001 From: CakeLancelot Date: Tue, 13 Feb 2024 03:17:25 -0600 Subject: [PATCH 3/4] dx2cg: Implement RECT, CUBE texture types Also tried to implement 3D texture type, but that will likely require a few other instructions to get working - namely texldp and dcl_volume. --- dx2cg/disassembler.py | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/dx2cg/disassembler.py b/dx2cg/disassembler.py index d3c1556..42d9a85 100644 --- a/dx2cg/disassembler.py +++ b/dx2cg/disassembler.py @@ -54,7 +54,7 @@ ops = { "slt": "{0} = float4(({1}.x < {2}.x) ? 1.0f : 0.0f, ({1}.y < {2}.y) ? 1.0f : 0.0f, ({1}.z < {2}.z) ? 1.0f : 0.0f, ({1}.w < {2}.w) ? 1.0f : 0.0f);", "sge": "{0} = float4(({1}.x >= {2}.x) ? 1.0f : 0.0f, ({1}.y >= {2}.y) ? 1.0f : 0.0f, ({1}.z >= {2}.z) ? 1.0f : 0.0f, ({1}.w >= {2}.w) ? 1.0f : 0.0f);", "rcp": "{0} = ({1} == 0.0f) ? FLT_MAX : (({1} == 1.0f) ? {1} : (1 / {1}));", - "texld": "{0} = tex2D({2}, (float2){1});", + "texld": "{0} = {3}({2}, (float2){1});", } struct_a2v = """struct a2v { @@ -186,12 +186,21 @@ def process_header(prog): i = i - 1 elif line.startswith("SetTexture"): dec = line.split(' ') - if dec[2] != "{2D}": + texture_type = None + if dec[2] == "{2D}": + texture_type = "sampler2D" + elif dec[2] == "{3D}": + texture_type = "sampler3D" + elif dec[2] == "{RECT}": + texture_type = "samplerRECT" + elif dec[2] == "{CUBE}": + texture_type = "samplerCUBE" + else: raise ValueError(f"Unknown texture type {dec[2]}") key = f"s{textures}" val = dec[1][1:-1] loctab[key] = val - locdecl.append(f"sampler2D {val};") + locdecl.append(f"{texture_type} {val};") textures = textures + 1 del prog[i] @@ -218,7 +227,6 @@ def resolve_args(args, loctab, consts): arg = arg[:dot] else: swiz = "" - if arg[0] == 'r': pass elif arg[0] == 'v': @@ -239,7 +247,7 @@ def resolve_args(args, loctab, consts): args[a] = neg + arg + swiz -def decode(code, args): +def decode(code, args, locdecl): if code in decls: return [decls[code].format(*args)] elif code in ops: @@ -254,14 +262,31 @@ def decode(code, args): else: swiz = "xyzw" - lines = [ops[code].format("tmp", *args[1:])] + lines = [] + if code == "texld": + cg_tex_type = None + for loc in locdecl: + loc = loc.split(' ') + if args[2] == loc[1][:-1]: + if loc[0] == 'sampler2D': + cg_tex_type = "tex2D" + elif loc[0] == 'sampler3D': + cg_tex_type = "tex3D" + elif loc[0] == 'samplerCUBE': + cg_tex_type = "texCUBE" + elif loc[0] == 'samplerRECT': + cg_tex_type = "texRECT" + lines = [ops[code].format("tmp", *args[1:], cg_tex_type)] + else: + lines = [ops[code].format("tmp", *args[1:])] + for c in swiz: lines.append(f"{target}.{c} = tmp.{c};") return lines else: raise ValueError(f"Unknown opcode {code}") -def process_asm(asm, loctab): +def process_asm(asm, loctab, locdecl): shadertype = "" if asm[0] == "\"vs_1_1": shadertype = "vertex" @@ -294,7 +319,7 @@ def process_asm(asm, loctab): code = code[:pp] resolve_args(args, loctab, consts) - disasm = decode(code, args) + disasm = decode(code, args, locdecl) # print(f"{instruction} \t==>\t{disasm}") disasm.insert(0, f"// {instruction}") translated.extend(disasm) @@ -317,7 +342,7 @@ def disassemble(blocks): binds.update(bds) lighting |= light - (shadertype, disasm) = process_asm(asm, ltab) + (shadertype, disasm) = process_asm(asm, ltab, locdecl) shaders[shadertype] = disasm text = "" From 672d7e2b427c407279eadfd0dcc95fa1fc27749f Mon Sep 17 00:00:00 2001 From: CakeLancelot Date: Wed, 14 Feb 2024 03:15:09 -0600 Subject: [PATCH 4/4] Address PR review comments --- dx2cg/disassembler.py | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/dx2cg/disassembler.py b/dx2cg/disassembler.py index 42d9a85..8957934 100644 --- a/dx2cg/disassembler.py +++ b/dx2cg/disassembler.py @@ -186,7 +186,6 @@ def process_header(prog): i = i - 1 elif line.startswith("SetTexture"): dec = line.split(' ') - texture_type = None if dec[2] == "{2D}": texture_type = "sampler2D" elif dec[2] == "{3D}": @@ -227,6 +226,7 @@ def resolve_args(args, loctab, consts): arg = arg[:dot] else: swiz = "" + if arg[0] == 'r': pass elif arg[0] == 'v': @@ -247,6 +247,22 @@ def resolve_args(args, loctab, consts): args[a] = neg + arg + swiz +def get_cgtex_type(name, locdecl): + for loc in locdecl: + loc = loc.split(' ') + if name == loc[1][:-1]: + if loc[0] == 'sampler2D': + return "tex2D" + elif loc[0] == 'sampler3D': + return "tex3D" + elif loc[0] == 'samplerCUBE': + return "texCUBE" + elif loc[0] == 'samplerRECT': + return "texRECT" + else: + raise ValueError(f"Unknown CG texture type {loc[0]}") + raise ValueError(f"Could not find texture {name} in locals") + def decode(code, args, locdecl): if code in decls: return [decls[code].format(*args)] @@ -262,21 +278,8 @@ def decode(code, args, locdecl): else: swiz = "xyzw" - lines = [] if code == "texld": - cg_tex_type = None - for loc in locdecl: - loc = loc.split(' ') - if args[2] == loc[1][:-1]: - if loc[0] == 'sampler2D': - cg_tex_type = "tex2D" - elif loc[0] == 'sampler3D': - cg_tex_type = "tex3D" - elif loc[0] == 'samplerCUBE': - cg_tex_type = "texCUBE" - elif loc[0] == 'samplerRECT': - cg_tex_type = "texRECT" - lines = [ops[code].format("tmp", *args[1:], cg_tex_type)] + lines = [ops[code].format("tmp", *args[1:], get_cgtex_type(args[2], locdecl))] else: lines = [ops[code].format("tmp", *args[1:])]