crosire / d3d8to9

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

Skip unneeded SetViewport calls #78

Closed elishacloud closed 6 years ago

elishacloud commented 6 years ago

Overview:

This pull fixes #76. It will skip unneeded calls to SetViewport.

The extra call to SetViewport causes an issue in Direct3D9, while Direct3D8 can handle it. I believe this is a bug in Hydorah because based on my testing even in Direct3D8 this call is not needed. But since Direct3D9 does not handle it the same as Direct3D8 I believe we should fix it.

This update makes the following changes: If SetViewport is called twice in the same frame and the only significant function called in between these two calls is SetTransform using D3DTS_VIEW it will skip the second call to SetViewport.

Significant calls are defined as:

Note: Hydorah calls the following three functions in this order:

SetViewport(0x0019FBCC);
SetTransform(D3DTS_VIEW, 0x0019FB80);
SetTransform(D3DTS_PROJECTION, 0x0019FB80);
Clear(0x00000000, NULL, 0x00000003, D3DCOLOR_ARGB(0xff,0x00,0x00,0x00), 1.000f, 0x00000000);
SetViewport(0x0019FBCC);        // <-- This one is not needed and gets skipped

Testing:

I tested this with the following games:

crosire commented 6 years ago

This is a weird bug. The only way I can explain this to myself is that SetViewport is affected by whatever view transform is currently set. In that case the cleaner solution would be to set the transform to the identity matrix before applying the viewport and then resetting it to whatever it was before. But I don't know if that's it.

elishacloud commented 6 years ago

Hold off on this pull request. I think I found the root cause. It looks like the call is failing in Direct3D8 because the parameters in SetViewport are wrong. The width and height are too large. As far as I can tell, Direct3D9 is also suppose to fail this call as well, but does not. I am working on a better fix for this but need to do more testing.

According to the documentation here it should "return D3DERR_INVALIDCALL ... if pViewport is invalid, or if pViewport describes a region that cannot exist within the render target surface."

It appears that Direct3D9 is still accepting the call even though the region "cannot exist within the render target surface."