crosire / d3d8to9

A D3D8 pseudo-driver which converts API calls and bytecode shaders to equivalent D3D9 ones.
BSD 2-Clause "Simplified" License
880 stars 78 forks source link

Convert to ps_1_4 #58

Closed elishacloud closed 6 years ago

elishacloud commented 6 years ago

Ok, I believe this is finally ready to check in. This has a few different updates in it, but the biggest change is the code to convert to ps_1_4. Let me describe the other changes first.

Sorry for the wall of text!

Code Changes:

1. Added some spaces to make the code more readable

See here and here for an example.

2. Changed the way Instruction/Arithmetic count is computed:

This is a realitivly small update but I changed from using int to using size_t and I changed from using atoi to using strtoul. This also changes from using a pointer and instead uses substr and c_str. See here and here.

3. Checks the destination register before updating the constant modifier:

Some games use a pixel shader that uses the same register for both the source and destination register along with a modifier on the constant. Example:

  + mul r0.w, 1-r0.w, 1-c0.w

Notice how r0 is used for both the source and destination.

The code used to change it to:

    mov r0, c0 /* added line*/
  + mul r0.w, 1-r0.w, 1-r0.w /* changed c0 to r0 */

This is obviously wrong, and I think it was part of the contributor to issue #44. Updated to fix this here.

4. Added code to convert to ps_1_4:

The logic here is fairly straight forward. Rather than describing it all (since you can just review the code), let me put a few notes about the logic:

Basic conversion logic:

Testing:

I tested this with the following games:

However because ps_1_4 conversion is only attempted if an exact conversion cannot be done without it, only three of the games actually use this code. All other games either don't use pixel shaders or can do exact conversion without needing ps_1_4.

1. Silent Hill 2

This should be a complete fix for Silent Hill 2 pixel shader issues. I was able to do an exact conversion. It also fixes issue #56.

Here is what the conversion looks like for one of the pixel shaders:

Previous d3d8to9 conversion

    ps_1_1
    tex t0
    tex t1
    tex t2
    dp3_sat r0, t2_bx2, c1 /* removed modifier _bx2 */
    dp3 r1.xyz, t2_bx2, v1_bx2
  + sub r0.w, r0, c2.w /* changed 'add' to 'sub' removed modifier - */
    mul_sat r1.xyz, r1, t0.w
    mul_sat r0.xyz, r0.w, r1
    mul r1.xyz, t1, t0.w
    mad_sat r0.xyz, r0, c2, v0
    mul r0.xyz, r0, t0
  + mov r0.w, t0.w
    mad r0.xyz, r1, c3, r0

ENBSeries conversion

    ps_1_4
    texld r1, t1
    texld r2, t2
    mov r3, c1
    phase
    texld r0, t0
    dp3_sat r3, r2_bx2, r3_bx2
    dp3 r2.xyz, r2_bx2, v1_bx2
  + sub r3.w, r3.x, c2.w
    mul_sat r2.xyz, r2, r0.w
    mul_sat r3.xyz, r3.w, r2
    mul r2.xyz, r1, r0.w
    mad_sat r3.xyz, r3, c2, v0
    mul r3.xyz, r3, r0
    mad r0.xyz, r2, c3, r3

Updated d3d8to9 conversion

    ps_1_4 /* converted */
    mov r3, c1
    phase
    texld r2, t2
    texld r1, t1
    texld r0, t0
    dp3_sat r3, r2_bx2, r3_bx2
    dp3 r2.xyz, r2_bx2, v1_bx2
  + sub r3.w, r3, c2.w /* changed 'add' to 'sub' removed modifier - */
    mul_sat r2.xyz, r2, r0.w
    mul_sat r3.xyz, r3.w, r2
    mul r2.xyz, r1, r0.w
    mad_sat r3.xyz, r3, c2, v0
    mul r3.xyz, r3, r0
  + mov r3.w, r0.w
    mad r0.xyz, r2, c3, r3

2. True Crime New York City

This update also fixes True Crime New York City pixel shader issues. Previous fixes for #44 would simply remove constant modifiers.

The ENBSeries converter also tries to convert pixel shaders to ps_1_4, but seems to crash with this game.

Previous d3d8to9 conversion

    ps_1_1
    tex t0
    tex t1
    mul r0, v0, t0
    mul r1, v1, t1
    mul r0.xyz, r0, r0.w
    lrp r0.xyz, c0.w, r1, r0
  + mul r0.w, 1-r0.w, c0.w /* removed modifier 1- */

Updated d3d8to9 conversion

    ps_1_4 /* converted */
    def c1, 0, 0, 0, 0 /* added line */
    phase
    texld r1, t1
    texld r0, t0
    mov r2, c0
    mul r0, v0, r0
    mul r1, v1, r1
    mul r0.xyz, r0, r0.w
    lrp r0.xyz, c0.w, r1, r0
  + mul r0.w, 1-r0.w, 1-r2.w

3. Star Wars Republic Commando

Unfortunately the code is not able to convert Star Wars Republic Commando to ps_1_4 because the pixel shaders here are already using 8 arithmetic instructions in phase 2 but they also require the mov instruction to be in phase 2. In addition the pixel shaders here use more than one texture register in the same instruction, which I am not sure how to covert to ps_1_4. Any attempted conversion here seems to cause incorrect texture lighting.

The pixel shader ps_1_4 conversion errors out here for this game and it continues using the previous logic. However, the game is fully playable and has no ill side effects (that I could find), other than the modifier is removed from a constant. See below pixel shader code.

The ENBSeries converter also crashes with this game. It seems that there is no easy way to convert these pixel shaders to ps_1_4.

Note: This is the only game of the ones above I tested that I am unable to do exact conversion from the d3d8 pixel shader to the d3d9 pixel shader.

Previous/current d3d8to9 conversion

    ps_1_1
    tex t0
    tex t1
    tex t2
    tex t3
    dp3_sat r0, t1_bx2, t2_bx2
    dp3_sat r1, t1_bx2, t3_bx2
    mad r0.xyz, r0, v1, v0
    sub_x2_sat r1, r1.w, c0 /* changed 'mad' to 'sub' removed r1.w removed modifier - */
    mul_sat r1, r1, v1
    mul r1, r1, t1.w
    lrp r0, t0.w, t0, r0
    mad_sat r0, r0, t0, r1

Error when trying to convert to ps_1_4

> Failed to convert shader to ps_1_4
> Dumping translated shader assembly:

    ps_1_4 /* converted */
    mov r4, c0
    phase
    texld r3, t3
    texld r2, t2
    texld r1, t1
    texld r0, t0
    dp3_sat r2, r1_bx2, r2_bx2
    dp3_sat r3, r1_bx2, r3_bx2
    mad r2.xyz, r2, v1, v0
    mad_x2_sat r3, r3.w, r3.w, -r4
    mul_sat r3, r3, v1
    mul r3, r3, r1.w
    lrp r2, r0.w, r0, r2
    mad_sat r2, r2, r0, r3

// approximately 12 instruction slots used (4 texture, 8 arithmetic)

> Failed to reassemble shader:

D:\Games\Star Wars - Republic Commando\GameData\System\memory(11,5): error X5119: Read of uninitialized component(*) in r4: r/x/0 g/y/1 b/z/2 *a/w/3. Note that an unfortunate effect of the phase marker earlier in the shader is that the moment it is encountered in certain hardware, values previously written to alpha in any r# register, including the one noted here, are lost. In order to read alpha from an r# register after the phase marker, write to it first.
crosire commented 6 years ago

Amazing work as always!