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

Fix GetContainer() function #98

Closed elishacloud closed 5 years ago

elishacloud commented 5 years ago

Background

I was reading the documentation here on the Microsoft site and it says:

If D3DXLoadSurfaceFromSurface is called and the surface was not already dirty (this is unlikely under normal usage scenarios), the application needs to explicitly call AddDirtyRect on the surface.

In attempting to fix this I planned to use the GetContainer function to get the texture and mark it dirty. However, noticed that the GetContainer function was broken in d3d8to9. In fixing GetContainer I decided to update QueryInterface also to handle cases that it could not handle before.

Fixes

This update has three changes in it:

Update QueryInterface

I created two new functions one called ConvertREFIID to convert d3d8 IIDs to d3d9 IIDs and the other called genericQueryInterface to take a d3d9 address and lookup the associated d3d8to9 wrapper address. Both of these functions are used in QueryInterface to handle the case where an application calls QueryInterface to get the address of a different interface.

I have seen at least one application (Star Wars Battlefront 2) do this type of thing in DirectX9 and many applications do this in DirectX7, so I assume the same issue could happen in DirectX8. Without this fix the result is typically a solid color screen (all white, all black, all blue, etc.) or the application will crash. Several open issues exhibit these symptoms, though I have not reproduces those issues myself.

Also note that in order to fix this I had to keep track of the current Direct3DDevice8 class address, since that was required to lookup the address in the address table. See variable pCurrentD3DDevice.

Fix GetContainer function

The GetContainer function can return an interface for whatever was requested. With this update the IID will be converted to a d3d9 IID and when an interface is returned it will do a lookup to find the associated d3d8to9 wrapper interface. Prior to this update the GetContainer function was broken.

Explicitly call AddDirtyRect on the surface after D3DXLoadSurfaceFromSurface

For this update when D3DXLoadSurfaceFromSurface is called I try and get the texture interface associated to the surface (if there is one) and mark the coordinates as "dirty". This does not completely address the Microsoft article quoted above, but should help in at least some cases. I thought about locking the surface, which would trigger the dirty flag also, but that could cause other unwanted side effects.

Also note that this fixes the return value in CopyRect when D3DXLoadSurfaceFromSurface is called. D3DXLoadSurfaceFromSurface can return D3DXERR_INVALIDDATA which is not a valid return error for CopyRect.