elishacloud / dxwrapper

Fixes compatibility issues with older games running on Windows 10/11 by wrapping DirectX dlls. Also allows loading custom libraries with the file extension .asi into game processes.
zlib License
1.17k stars 83 forks source link

Call of Duty 4 fails when creating the `D3DFMT_R32F` render target #52

Open copslock opened 4 years ago

copslock commented 4 years ago

Hello Elisha! It's great lucky to find some code of Direct3D API logging but as you told this layer can be used to modify the D3D API calls from game program,so I'm thinking about solving an historical problem that annoying me for years----the Call of Duty 4(iw3 engine) on Intel GMA Gen3(900/950/3100/3150) GPUs. The problem is the game will failed with Create2DTexture( $floatz, 640, 480, 0, 114 ) failed: 8876086c = Invalid call By analyzing the API calls of iw3sp.exe,I found that after the creation of D3D window,the program send such command IDirect3DDevice9_CreateTexture, IDirect3DDevice9P<11a208a8>, UINT<280>, UINT<1e0>, UINT<1>, DWORD<1>, D3DFORMAT<**D3DFMT_R32F**>, D3DPOOL<D3DPOOL_DEFAULT>, IDirect3DTexture9PP<1d43614>, HANDLEP<0>, Format<72>, D3DFORMAT<**D3DFMT_R32F**>no POW2 texture!!! no POW2 texture!!! , HRESULT<8876086c> As the code above,the program send rendering command using D3DFMT_R32F format,and according to the header file of swiftshader(https://github.com/bkaradzic/SwiftShader/blob/master/src/D3D9/Direct3D9.cpp)

case D3DRTYPE_SURFACE:
            if(usage & D3DUSAGE_RENDERTARGET)
            {
                switch(checkFormat)
                {
                case D3DFMT_NULL:           if(!Capabilities::Surface::RenderTarget::NULL_)         return NOTAVAILABLE();  else return D3D_OK;
                case D3DFMT_R8G8B8:         if(!Capabilities::Surface::RenderTarget::R8G8B8)        return NOTAVAILABLE();  else return D3D_OK;
                case D3DFMT_R5G6B5:         if(!Capabilities::Surface::RenderTarget::R5G6B5)        return NOTAVAILABLE();  else return D3D_OK;
                case D3DFMT_X1R5G5B5:       if(!Capabilities::Surface::RenderTarget::X1R5G5B5)      return NOTAVAILABLE();  else return D3D_OK;
                case D3DFMT_A1R5G5B5:       if(!Capabilities::Surface::RenderTarget::A1R5G5B5)      return NOTAVAILABLE();  else return D3D_OK;
                case D3DFMT_A4R4G4B4:       if(!Capabilities::Surface::RenderTarget::A4R4G4B4)      return NOTAVAILABLE();  else return D3D_OK;
                case D3DFMT_R3G3B2:         if(!Capabilities::Surface::RenderTarget::R3G3B2)        return NOTAVAILABLE();  else return D3D_OK;
                case D3DFMT_A8R3G3B2:       if(!Capabilities::Surface::RenderTarget::A8R3G3B2)      return NOTAVAILABLE();  else return D3D_OK;
                case D3DFMT_X4R4G4B4:       if(!Capabilities::Surface::RenderTarget::X4R4G4B4)      return NOTAVAILABLE();  else return D3D_OK;
                case D3DFMT_A8R8G8B8:       if(!Capabilities::Surface::RenderTarget::A8R8G8B8)      return NOTAVAILABLE();  else return D3D_OK;
                case D3DFMT_X8R8G8B8:       if(!Capabilities::Surface::RenderTarget::X8R8G8B8)      return NOTAVAILABLE();  else return D3D_OK;
                case D3DFMT_A8B8G8R8:       if(!Capabilities::Surface::RenderTarget::A8B8G8R8)      return NOTAVAILABLE();  else return D3D_OK;
                case D3DFMT_X8B8G8R8:       if(!Capabilities::Surface::RenderTarget::X8B8G8R8)      return NOTAVAILABLE();  else return D3D_OK;
                // Integer HDR formats
                case D3DFMT_G16R16:         if(!Capabilities::Surface::RenderTarget::G16R16)        return NOTAVAILABLE();  else return D3D_OK;
                case D3DFMT_A2B10G10R10:    if(!Capabilities::Surface::RenderTarget::A2B10G10R10)   return NOTAVAILABLE();  else return D3D_OK;
                case D3DFMT_A2R10G10B10:    if(!Capabilities::Surface::RenderTarget::A2R10G10B10)   return NOTAVAILABLE();  else return D3D_OK;
                case D3DFMT_A16B16G16R16:   if(!Capabilities::Surface::RenderTarget::A16B16G16R16)  return NOTAVAILABLE();  else return D3D_OK;
                // **Floating-point formats**
                case D3DFMT_R16F:           if(!Capabilities::Surface::RenderTarget::R16F)          return NOTAVAILABLE();  else return D3D_OK;
                case D3DFMT_G16R16F:        if(!Capabilities::Surface::RenderTarget::G16R16F)       return NOTAVAILABLE();  else return D3D_OK;
                case D3DFMT_A16B16G16R16F:  if(!Capabilities::Surface::RenderTarget::A16B16G16R16F) return NOTAVAILABLE();  else return D3D_OK;
                case **D3DFMT_R32F**:           if(!Capabilities::Surface::RenderTarget::R32F)          return NOTAVAILABLE();  else return D3D_OK;
                case D3DFMT_G32R32F:        if(!Capabilities::Surface::RenderTarget::G32R32F)       return NOTAVAILABLE();  else return D3D_OK;
                case D3DFMT_A32B32G32R32F:  if(!Capabilities::Surface::RenderTarget::A32B32G32R32F) return NOTAVAILABLE();  else return D3D_OK;
                default:
                    return NOTAVAILABLE();
                }
            }

The D3DFMT_R32F render target is actually Floating-point render target format,such format is avaliable even on the Geforce FX5200,but nor the Intel. In the develop guide of GMA900(Same Gen3 core of GMA3100) P16 https://software.intel.com/sites/default/files/m/d/4/1/d/8/Intel_915G_SDG_Feb05.pdf And the introduction of Intel X3000 Unified gpu architecture P13 https://www.intel.com/Assets/PDF/whitepaper/313343.pdf Intel said it only supports fix-point render target and do not support the floating-type on Gen3 architecture. So everything becomes clear,it's here any possible to modify the HRESULT of that call to SUCCESS or much better converting it into equally fix-point type instruction? Some guys may talk with me that the Intel GMA3100 is completely crap and don't waste time on such rubbish but as you know in the old days of 2007-era even such crappy GPU gives much more pleasure than today's TitanX,but at that time I wasn't know very much about programming and it's quite regretful at that time.It's 10 years later and I'm finally be able to find what is going on with that game.Hope you can give a little advice to solve this problem Best regards

mirh commented 4 years ago

Tbh I would wholeheartedly recommend to switch to linux on such hardware (more specifically manjaro32, I don't know other 32 bit distros with hope). Wine should take care of games, and where it would be bugged or not performant enough, I'd be pretty sure some developer can get behind helping you with anything.

But by all means.. This is really the super dope kind of stuff that I always expected dxwrapper to be able to uniquely fixing.

elishacloud commented 4 years ago

it's here any possible to modify the HRESULT of that call to SUCCESS

Technically this can be done, but this will most likely just crash the game or have no effect. The fix for this is a bit more complex.

or much better converting it into equally fix-point type instruction?

I don't think there is an equivalent fixed point substitute. However, since this is most likely used for shadowing or for lighting, the best alternative format may be D3DFMT_G16R16. I could simply just convert this one API call to use format D3DFMT_G16R16, but it would likely require more work than just that. I really need to test it with this game to see what other functions are used by this texture and how these functions can be converted to use the new texture format.

I don't really have time to look at it right now. But I will take a look at it when I get time. As @mirh, suggested this is most likely something I would add to the dxwrapper project.