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

Update CreateVertexShader to fix missing textures #27

Closed elishacloud closed 7 years ago

elishacloud commented 7 years ago
PatrickvL commented 7 years ago

Nice work! As for the zbias to depthbias mapping - I choose the same mapping a few years ago - see https://github.com/PatrickvL/Dxbx/blob/master/Source/Delphi/src/DxbxKrnl/EmuD3D8/uConvert.pas#L436 this might contain other mappings that could be useful for this project (although to be honest, these weren't tested thoroughly, so I'm not 100% sure those mappings in there are entirely correct, but at least it's a reference that can be looked at, right?)

elishacloud commented 7 years ago

Yes, changing D3DRS_ZBIAS to D3DRS_DEPTHBIAS may not be a perfect change. However if you look at Direct3DDevice8::GetRenderState it appears that this is what d3d8to9 is expecting. There are other ways of handling this also. Take a look at the comments here and here.

It seems that the Boris/ENBSeries converter does something similar to what d3d8to9 does. Here is what ENBSeries does:

case D3DRS_ZBIAS:
    Biased = static_cast<FLOAT>(Value) * -0.0f;
    Value = *reinterpret_cast<const DWORD *>(&Biased);
    State = D3DRS_DEPTHBIAS;
    SetRenderState(State, Value);
    break;

Whereas d3d8to9 does this:

case D3DRS_ZBIAS:
    Biased = static_cast<FLOAT>(Value) * -0.000005f;
    Value = *reinterpret_cast<const DWORD *>(&Biased);
    State = D3DRS_DEPTHBIAS;
    SetRenderState(State, Value);
    break;

I am not quite sure which one is better. All five games I tested showed the same results no matter which one of these methods I used. So I took the simplest path.

As far as the fix for CreateVertexShader, I did notice that d3d8to9 will initialize all three registers: 'oD', 'oT' and 'r'. However the ENBSeries only initializes the 'oT' registers. I did not see a need to initialize the 'oD' and 'r' registers but I left them there as it seemed to work. Though I wonder if initializing these other two registers are really needed.

crosire commented 7 years ago

There was a game (the first Max Payne I think) that would only write to certain components of some registers, leaving the rest uninitialized. Passing that code to the D3DX assembler would fail with an error, which is why the initialization happens. I don't know if this works even if c0 is not declared, since it's a constant either way. But it probably will, so I guess it's OK.

elishacloud commented 7 years ago

I tested both Max Payne and Max Payne 2.

Max Payne fails both with and without this change and never calls CreateVertexShader. Something weird is happening with Max Payne because it appears that all APIs are already hooked and it won't launch if I try to attach a debugger to it or run it with PIX. I cannot get Max Payne to work with d3d8to9 even with older versions of d3d8to9.

Max Payne 2 seems to run fine with d3d8to9 with this change.

Let me know if there is some other issue with this change. It seems to work fine on all the games I have tested.

crosire commented 7 years ago

Alright. Looks good then.