Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spy-vs-Spy: Main menu geometry is corrupt #1072

Closed
abaire opened this issue Jun 17, 2022 · 12 comments · Fixed by #1080
Closed

Spy-vs-Spy: Main menu geometry is corrupt #1072

abaire opened this issue Jun 17, 2022 · 12 comments · Fixed by #1080
Labels
bug Something isn't working

Comments

@abaire
Copy link
Contributor

abaire commented Jun 17, 2022

Title

https://xemu.app/titles/5454007c/#Spy-vs-Spy

Bug Description

Note: This is an intentional dup of the generic #309 and #537 so I have a place to put my game-specific analysis.

The main menu in Spy Vs Spy renders with highly distorted geometry, most of the draws are clipped entirely due to the fact that the w component of the programmable vertex shader is very negative.

E.g., one of the screen space vertices: {320.7315979004, 253.5145263672, 49013.19921875, -100978.4765625}

Screenshot_20220617_070622

Expected Behavior

The menu should not be corrupted, and draws should generally be unclipped and projected properly.

xemu Version

Happens in 0.7.39 and has apparently been happening for a long time (or forever), at least since 0.6.2

System Information

CPU: Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz
OS Platform: Linux
OS Version: Ubuntu 21.10
Manufacturer: NVIDIA Corporation
GPU Model: NVIDIA GeForce GTX 1070/PCIe/SSE2
Driver: 4.0.0 NVIDIA 470.129.06
Shader: 4.00 NVIDIA via Cg compiler

Additional Context

The game uses S32K mode for the vertex positions, which is not something I've come across before. I wrote a quick test to validate xemu's behavior and it seems to align with what I see in HW, so there's something else going on here.

@abaire abaire added the bug Something isn't working label Jun 17, 2022
@abaire
Copy link
Contributor Author

abaire commented Jun 17, 2022

Vertex shader:

MUL oT0.x, v0.wxyz, c[120].zx + MUL R0.yzw, v0.wxyz, c[120].zx
MOV R0.x, c[125].z
DP4 R11.z, R0.yzwx, c[98]
DP4 R11.x, R0.yzwx, c[96]
DP4 R11.y, R0.yzwx, c[97]
ADD R10.xyzw, v2, c[129]
DP4 oPos.w, R0.yzwx, c[99]
MUL R10.xyzw, c[121], R10 + MOV oPos.xyz, R11
MUL oT0.y, v1.w, c[120].z + RCC R1.x, R12.w
MUL oPos.xyz, R12.xyz, c[58].xyz
MAD oFog.xyzw, R11.z, c[108].x, c[108].y
MUL oD0.w, R10.w, c[125].x
MOV oD0.xyz, R10
MAD oPos.xyz, R12.xyz, R1.x, c[59].xyz

Filtered for the bits that contribute to oPos:

MUL R0.yzw, v0.wxyz, c[120].zx
MOV R0.x, c[125].z
DP4 R11.z, R0.yzwx, c[98]
DP4 R11.x, R0.yzwx, c[96]
DP4 R11.y, R0.yzwx, c[97]
DP4 oPos.w, R0.yzwx, c[99]
MOV oPos.xyz, R11
RCC R1.x, R12.w
MUL oPos.xyz, R12.xyz, c[58].xyz
MAD oPos.xyz, R12.xyz, R1.x, c[59].xyz

Some initial values:

v0: 89, 5156, -151, 417
c[58] 320.00, -240.00, 16777215.00, 0.00
c[59] 320.03125, 240.03125, 0.00, 0.00 
c[96] 1.00, 0.00, 0.00, 0.00 
c[97] 0.00, 1.00, 0.00, 0.00 
c[98] 0.00, 0.00, 1.00, 0.00 
c[99] -16.8876857758, -18.2681617737, 3.6487216949, 1.00 
c[120] 1.00, 0.0000610352, 0.0009765625, 1.00
c[125] 1.00, 1.00, 1.00, 0.00 

Some values stepping through with the above inputs (in xemu):

MUL R0.yzw, v0.wxyz, c[120].zx
MOV R0.x, c[125].z

> R0 = 1, 89, 5156, -151

DP4 R11.z, R0.yzwx, c[98]
DP4 R11.x, R0.yzwx, c[96]
DP4 R11.y, R0.yzwx, c[97]

> R11 = 89, 5156, -151, 0

DP4 oPos.w, R0.yzwx, c[99]
MOV oPos.xyz, R11

> oPos = 89, 5156, -151, -96243.6015625

RCC R1.x, R12.w

> R1.x = -0.0000103903

MUL oPos.xyz, R12.xyz, c[58].xyz

> oPos = 28480, -1237440, -2533359360, -96243.6015625

MAD oPos.xyz, R12.xyz, R1.x, c[59].xyz

> oPos = 319.7353210449, 252.8886260986, 26322.3671875,-96243.6015625

@abaire
Copy link
Contributor Author

abaire commented Jun 17, 2022

Surprisingly, running this test with the same shader and same inputs on HW gives the same unusual values:

Spyvsspymenu

So it would appear that this may not be a problem with the programmable part of the vertex shader but rather with how xemu is processing the negative w coord?

@abaire
Copy link
Contributor Author

abaire commented Jun 17, 2022

I see unhandled pgraph commands between 0x1e80 and 0x1e90 in the logs but they only happen after some of the draws. They also happen in a potentially interesting sequence; vertex shader constants start loading at 0x60 (96, the start of the typical user-configurable constant range), then 0x1e80,84,88,8c, 90, then constants continue loading at 0x7D (125).
The values passed to the 1e80-8c vary, but 1e90 is always called with 0x3C (60).

@jackchentwkh
Copy link

jackchentwkh commented Jun 17, 2022

I did investigated this game last year with no progress. but your finding are meaningful.
pgraph methods 1e80 to 1e8c are NV097_SET_TRANSFORM_DATA
and 1e90 is NV097_LAUNCH_TRANSFORM_PROGRAM
so clearly these methods are used to transform certain vertices. too bad these methods are not implemented yet.
for 1e80~1e8c, they are easy, simple register read and write.
1e90 is the key.

@jackchentwkh
Copy link

jackchentwkh commented Jun 18, 2022

ok, after a quick reverse engineering and study, here I have some findings.

  1. 0x1e8x NV097_SET_TRANSFORM_DATA is supposed to be an array of four float values that are assigned to the V0 register used in vertex shader.
  2. 0x1e90 NV097_LAUNCH_TRANSFORM_PROGRAM shall launch the vertex shader inside GPU, and the argument comes with it is the starting point (slot) of the vertex shader, which shall be sitting within 0 to 135.

@abaire
Copy link
Contributor Author

abaire commented Jun 18, 2022

Interesting, though if that's the case I'm now even more confused about what it does...

The transform program that is loaded in the frame is 14 slots, though it's possible that there's a longer program that was loaded earlier during the startup sequence that I didn't capture in my pgraph trace. I suppose it is possible that such a shader could be set up to write to the c registers or it could be populating some output that isn't set by the 14 slot shader above, but the constants used by the 14 slot shader are all explicitly set, and the input values are also explicitly set via NV097_SET_VERTEX_DATA_ARRAY invocations (v0, v1, and v2 are all populated just before the draw).

@jackchentwkh
Copy link

jackchentwkh commented Jun 18, 2022

The shaders could be loaded independently. User can assign the starting slot dusting each load.
The usages of these methods are vertex state shaders. These info are collected by reversing Xbox d3d RunVertexStateShader()
And yes, the sample code from xdk for vertex state shader is mean to alter C registers. Vertex state shader is not associate to vertex stream.

@abaire
Copy link
Contributor Author

abaire commented Jun 18, 2022

Yeah, that's what I assumed as well. I did a more extensive trace (took a bit as I had to write a utility to convert from pgraph trace to nv2a-vsh asm) and it is explicitly loading a context setting program:

Shader at 0x3c (60)
MOV R2.xyzw, c[96]
MOV R3.xyzw, c[97]
MOV R4.xyzw, c[98]
MOV R5.xyzw, c[99]
DP4 c[104].y, R3, c[92]
MUL R8.xyzw, R4, v0.z
MUL R6.xyzw, R2, v0.x
DP4 c[104].x, R2, c[92]
DP4 c[105].x, R2, c[93]
DP4 c[106].x, R2, c[94]
DP4 c[107].x, R2, c[95]
DP4 c[105].y, R3, c[93]
DP4 c[106].y, R3, c[94]
DP4 c[107].y, R3, c[95]
DP4 c[104].z, R4, c[92]
DP4 c[105].z, R4, c[93]
DP4 c[106].z, R4, c[94]
DP4 c[107].z, R4, c[95]
DP4 c[104].w, R5, c[92]
DP4 c[105].w, R5, c[93]
DP4 c[106].w, R5, c[94]
DP4 c[107].w, R5, c[95]
MUL R7.xyzw, R3, v0.y
MUL R9.xyzw, R5, v0.w
DP4 c[100].x, R6, c[92]
DP4 c[101].x, R6, c[93]
DP4 c[102].x, R6, c[94]
DP4 c[103].x, R6, c[95]
DP4 c[100].y, R7, c[92]
DP4 c[101].y, R7, c[93]
DP4 c[102].y, R7, c[94]
DP4 c[103].y, R7, c[95]
DP4 c[100].z, R8, c[92]
DP4 c[101].z, R8, c[93]
DP4 c[102].z, R8, c[94]
DP4 c[103].z, R8, c[95]
DP4 c[100].w, R9, c[92]
DP4 c[101].w, R9, c[93]
DP4 c[102].w, R9, c[94]
DP4 c[103].w, R9, c[95]
DP4 c[96].x, R6, c[88]
DP4 c[97].x, R6, c[89]
DP4 c[98].x, R6, c[90]
DP4 c[99].x, R6, c[91]
DP4 c[96].y, R7, c[88]
DP4 c[97].y, R7, c[89]
DP4 c[98].y, R7, c[90]
DP4 c[99].y, R7, c[91]
DP4 c[96].z, R8, c[88]
DP4 c[97].z, R8, c[89]
DP4 c[98].z, R8, c[90]
DP4 c[99].z, R8, c[91]
DP4 c[96].w, R9, c[88]
DP4 c[97].w, R9, c[89]
DP4 c[98].w, R9, c[90]
DP4 c[99].w, R9, c[91]

Unfortunately this will be non-trivial to implement as we don't have a good way to emulate writable c-registers.

It looks like all of the important registers other than c[125] would be modified by this shader and thus may not match the values being used by xemu. The other constants are all set before the LAUNCH is invoked.

@jackchentwkh
Copy link

Damn you’re quick!
Hand crafting a code to verify the result is the quickest way I guess.

@abaire
Copy link
Contributor Author

abaire commented Jun 19, 2022

Confirmed that implementing these two commands fixes the menu.

Screen Shot 2022-06-19 at 15 07 47

@jackchentwkh
Copy link

did you press the START and check the in game renderings? the in game renderings uses to have similar issues, should be fixed as well.

@abaire
Copy link
Contributor Author

abaire commented Jun 20, 2022

I've never actually played the game on HW before and am away from my Xbox for the next few days (I bought it specifically because it was broken in xemu and dumped it), but in-game looks reasonable to me at a glance.

Screen Shot 2022-06-19 at 21 18 17

abaire added a commit to abaire/xemu that referenced this issue Jun 20, 2022
abaire added a commit to abaire/xemu that referenced this issue Jun 20, 2022
abaire added a commit to abaire/xemu that referenced this issue Jun 22, 2022
abaire added a commit to abaire/xemu that referenced this issue Jun 24, 2022
abaire added a commit to abaire/xemu that referenced this issue Jun 24, 2022
abaire added a commit to abaire/xemu that referenced this issue Jun 25, 2022
abaire added a commit to abaire/xemu that referenced this issue Jun 25, 2022
abaire added a commit to abaire/xemu that referenced this issue Jun 25, 2022
abaire added a commit to abaire/xemu that referenced this issue Jun 25, 2022
abaire added a commit to abaire/xemu that referenced this issue Jun 25, 2022
mborgerson pushed a commit that referenced this issue Jun 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants