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

Can't wrap custom d3d8.dll with d3d8to9 #134

Closed
BC46 opened this issue Sep 18, 2021 · 75 comments
Closed

Can't wrap custom d3d8.dll with d3d8to9 #134

BC46 opened this issue Sep 18, 2021 · 75 comments

Comments

@BC46
Copy link
Contributor

BC46 commented Sep 18, 2021

I'm trying to run a game with a d3d8.dll from an older Windows 10 version that fixes some lighting-related issues the game has with the default Windows 10 d3d8.dll. Additionally, I'd like to wrap the older d3d8.dll with d3d8to9 so I can enable AF and AA.

This is what I have in my game folder:
dxwrapper.dll
dxwrapper.ini with the following config:

[Compatibility]
D3d8to9                    = 1

[d3d9]
AnisotropicFiltering       = 16
AntiAliasing               = 1

This file includes all the other values in the default dxwrapper.ini file, but those have not been changed from their defaults.
d3d8.dll from the Stub folder
d3d8.ini with the following config:

;; Config file for Stub to dxwrapper
[General]
RealDllPath       = Custom\d3d8.dll
WrapperMode       = d3d8.dll
StubOnly          = 0
LoadFromMemory    = 0

Custom\d3d8.dll. This is the custom d3d8.dll that I want to load instead of the default Windows 10 one.

With all these files and configs, d3d8to9 seems to load since the AF and AA are both working. However, it also seems the default Windows 10 d3d8.dll has loaded instead of the custom one, since the lighting bug is present in the game.

When I change D3d8to9 in dxwrapper.ini from 1 to 0, the exact opposite happens; the custom d3d8.dll loads, which has resulted in the lighting bug being gone, but obviously now d3d8to9 doesn't load as there is no AF nor AA.

It seems like I can only get one or the other to work simultaneously, but I'd like d3d8to9 to wrap the custom d3d8.dll. Am I missing something or is it impossible to get the result I'm trying to achieve here?

I'm using DxWrapper v1.0.6542.21. (latest release)

@mirh
Copy link

mirh commented Sep 18, 2021

You should also open another issue about that lighting bug, since it's kinda within the aims of dxwrapper to fix too.

@BC46
Copy link
Contributor Author

BC46 commented Sep 25, 2021

You should also open another issue about that lighting bug, since it's kinda within the aims of dxwrapper to fix too.

I wasn't sure if I was supposed to do this since it's a very specific issue. But I'll do it, thanks for letting me know.

@BC46
Copy link
Contributor Author

BC46 commented Sep 30, 2021

I decided to run the debug version of DxWrapper to see if that would show useful logs.

With the same config as before and D3d8to9 set to 0, it outputs this in the log:

20000 23:38:42.140 Wrapping 'd3d8.dll'...
20000 23:38:42.141 Loading 'Custom\d3d8.dll' as real dll...

The custom d3d8.dll loads correctly and works fine in-game here.

Now with D3d8to9 set to 1, those 2 lines no longer show in the output. It doesn't even mention anything about a d3d8.dll, which leads me to believe that it simply loads the default Windows 10 one.

@dmutlu
Copy link

dmutlu commented Sep 1, 2022

I am able to replicate this behavior on my system. It seems setting "D3d8to9" to true prevents the running of whatever DLL is specified in "RealDLLPath". Attached is two screenshots from ProcExp showing the result of flipping "D3d8to9" between true/false.

D3d8to9 = 1
Screenshot_D3d8to9_true

D3d8to9 = 0
Screenshot_D3d8to9_false

I am a novice when it comes to C++ but I am trying my best to look through the code to see why this is. My guess is maybe the logic/issue involves lines 187 and 435 of Dllmain.cpp.

My two theories:

  1. This is not a feature and dxwrapper never passes the DLL specified in Config.RealDLLPath to the D3d8to9 module.
  2. This is a feature but there is a conditional statement somewhere incorrectly preventing the passing of the specified RealDLLPath to the D3d8to9 module.

@elishacloud
Copy link
Owner

I am a novice when it comes to C++ but I am trying my best to look through the code to see why this is.

This is nothing to do with the C++ code. If you convert the game to use d3d9 (using d3d8to9) then it does no good to load a 3rd party d3d8.dll since the game is using d3d9 not d3d8.

Think about it this way, all 3rd party wrappers are hard coded to load the System32 dll files. So a 3rd party d3d8.dll wrapper will load System32 d3d8.dll. It looks like this:

Game -> (dxwrapper) d3d8.dll -> (3rd party) d3d8.dll -> (System32) d3d8.dll

However, when using 'd3d8to9' dxwrapper will load d3d9.dll rather than d3d8.dll like this:

Game -> (dxwrapper) d3d8.dll -> d3d9.dll

If dxwrapper tries to load a 3rd party dll before loading d3d9.dll then there will be no way for the game to use d3d9. See below:

Game -> (dxwrapper) d3d8.dll -> (3rd party) d3d8.dll -> (System32) d3d8.dll

There are two ways around this. The first way around this would be to hook the System32 d3d8.dll functions so that when the game calls them it will go back to dxwrapper, like this:

Game -> (dxwrapper) d3d8.dll -> (3rd party) d3d8.dll -> (System32 - hooked) d3d8.dll -> (dxwrapper) d3d8.dll -> d3d9.dll

The other solution is to modify the 3rd party wrapper to have it load dxwrapper rather than the System32 d3d8.dll, like this:

Game -> (3rd party) d3d8.dll -> (dxwrapper) d3d8.dll -> d3d9.dll

All this to say that it is a lot more work to support loading a 3rd party d3d8.dll and d3d8to9 at the same time. I have done a few custom developments of this (see here and here for examples). In both of these cases I chose to modify the 3rd party dll since that was the easier solution. I have thought about making a feature in dxwrapper to support this but I probably won't get around to it anytime soon.

Note: if you just want the dll to be loaded you can use either the 'LoadCustomDllPath' or the 'LoadPlugins' feature of dxwrapper.

@dmutlu
Copy link

dmutlu commented Sep 3, 2022

Thank you for the response and explanation @elishacloud, I appreciate it. In this specific use case the "3rd-party" dll is just an older version of Microsoft's d3d8.dll from Windows 10 19H1. Post 20H1 Microsoft seems to have replaced the d3d8.dll found in the System32 dir with d3d8thk.dll. This new version seems to carry some regressions in terms of lighting and shadows, specifically for the game Freelancer, which I guess folks will have to live with for now.

@elishacloud
Copy link
Owner

If you are using Microsoft's d3d8.dll then enabling d3d8to9 will by pass that and use d3d9.dll instead.

Does d3d8to9 work ok with Windows 10 19H1? What if you try the d3d9.dll from Windows 10 19H1? Just drop it in the game folder along with dxwrapper and enabled3d8to9. Does it work then?

Can you give more details on the lighting issue? Maybe this is something we can fix in d3d8to9?

@dmutlu
Copy link

dmutlu commented Sep 7, 2022

Does d3d8to9 work ok with Windows 10 19H1?

Not sure, I am running it in a VM just so I can grab the DLLs. Maybe @BC46 can answer since they originally found the older DLL trick.

What if you try the d3d9.dll from Windows 10 19H1? Just drop it in the game folder along with dxwrapper and enabled3d8to9. Does it work then?

I just tried this, I can see that dxwrapper is loading the older d3d9.dll but I am still seeing the lighting / shading issue.
Screenshot 2022-09-07 095323

Can you give more details on the lighting issue? Maybe this is something we can fix in d3d8to9?

Sure, I have attached a zip with two comparison screenshots (and also my dxwrapper log during the older d3d9.dll test). But here is a description of what we are seeing if you do not want to download the zip.

Issue: In specific interior locations lighting, shading, and transparency is broken with d3d9.dll

  1. Objects (ships, NPCs, crates, clutter) that interact with scene lighting appear fullbright, having no shading.
  2. Some interior level windows lose transparency, becoming opaque (black in color).

20220907.zip

Side Note:
Just to correct my past self and for any future readers. I mentioned that d3d8.dll was replaced in later builds of Windows 10, this was an incorrect assumption I made. For some reason I was not thinking about the WoW64 dir which actually stores the d3d8.dll. I guess my brain is just stuck on 64 bit these days...

@elishacloud
Copy link
Owner

Does d3d8to9 work ok with Windows 10 19H1?

Not sure, I am running it in a VM just so I can grab the DLLs. Maybe @BC46 can answer since they originally found the older DLL trick.

It would be good to know if d3d8to9 had an issue on the older Windows 10 with this game. I think the solution may be to fix d3d8to9 so that it does not have this lighting issue. In fact, does the lighting issue happen when using d3d8to9 on older OS's, like Windows 7, with this game?

BTW: I'm not sure, but I think maybe the change that Microsoft did after Windows 10 19H1 was to redirect Direct3D8 to go to the Driect3D9 drivers.

@BC46
Copy link
Contributor Author

BC46 commented Sep 7, 2022

It would be good to know if d3d8to9 had an issue on the older Windows 10 with this game.

I have a PC running Windows 10 19H1 which I use for compatibility testing. I played Freelancer (the game in question) using just d3d9to9 on it and it ran completely fine without the lighting bug.

Windows 10 version 2004 (20H1), or build 19041 is the first known Windows version where the lighting bug appears. People started reporting this issue shortly after the release date of this build. Players who still use Windows 7 & 8 to play this game can confirm that they've never encountered the issue before. However, these older Windows releases, including Vista and even newer XP service packs do all have a Freelancer DirectX compatibility issue regarding glass reflections on the ship windows. However, it's so minor that it's hardly worth mentioning. As far as I know, dgVoodoo is the only graphics wrapper that fixes both the lighting bug and the glass reflections issue properly on modern Windows versions.

In fact, does the lighting issue happen when using d3d8to9 on older OS's, like Windows 7, with this game?

I currently don't have access to a PC/VM running such older versions of Windows. Though I think it's unlikely that d3d8to9 could be the culprit since the lighting bug seems to show depending on the Windows version/build, regardless of whether d3d8to9 is used.

BTW: I'm not sure, but I think maybe the change that Microsoft did after Windows 10 19H1 was to redirect Direct3D8 to go to the Driect3D9 drivers.

All I know myself is that the DirectX rendering pipeline has been heavily modified since the release of Windows 10 2004, which I'm assuming is the cause of the lighting bug.

@elishacloud
Copy link
Owner

It would be good to know if d3d8to9 had an issue on the older Windows 10 with this game.

I have a PC running Windows 10 19H1 which I use for compatibility testing. I played Freelancer (the game in question) using just d3d9to9 on it and it ran completely fine without the lighting bug.

Ok, it sounds like d3d8to9 is not causing the issue. Have you tried using d3d8to9 and then using Direct3D9 to Vulkan? This way you can bypass whatever the Windows bug is.

@BC46
Copy link
Contributor Author

BC46 commented Sep 7, 2022

Yes, I tried that a while ago. I tested Freelancer using d3d8to9 + DXVK's d3d9.dll. This actually did fix the lighting bug, as a matter of fact. However, DXVK also introduced several compatibility issues in Freelancer specifically, such as inconsistent stutters and LOD models not always being displayed correctly. Hence I prefer using different solutions to counter the lighting bug.

@elishacloud
Copy link
Owner

I see. Maybe I should fix the lighting issue in my d3d9 wrapper? The way I have coded the d3d8to9 function is that it goes through the d3d9 wrapper. So any d3d9 fixes I add will also fix d3d8to9.

@BC46
Copy link
Contributor Author

BC46 commented Sep 9, 2022

If you think it's worth the effort, then that would be amazing. I'll provide any additional info and help if needed.

@BC46
Copy link
Contributor Author

BC46 commented Mar 3, 2023

I wanted to do some more research and @elishacloud's info regarding Direct3D8 being redirected to the Direct3D9 drivers after Windows update 19H1 gave me some clues as to where I could look.

First I should mention how Freelancer makes use of DirectX 8's lights. Basically the game uses so-called Thorn scripts to specify what kind of lights should be used in a scene. Inherently these are just compressed Lua scripts. Here's an example of how a light is set in one of the scripts that has been decompressed:

{
	entity_name  =  "ambi_LtG03_Basement_Ohd_Ylw",
	type  =  LIGHT,
	template_name  =  "",
	lt_grp  =  3, srt_grp  =  0, usr_flg  =  0,
	spatialprops  = 
	{
		pos  =  { -5.010058, 0, 1.758013 },
		orient  =  { { -0.105263, -0.008535, -0.994408 },
				   { 0.977260, 0.184208, -0.105029 },
				   { 0.184075, -0.982850, -0.011049 } }
	},
	lightprops  = 
	{
		on  =  Y,
		color  =  { 234, 192, 115 },
		diffuse  =  { 0.623529, 0.576471, 0.376471 },
		specular  =  { 0, 0, 0 },
		ambient  =  { 0.086275, 0.086275, 0.07451 },
		direction  =  { 0, 0, 1 },
		range  =  100,
		cutoff  =  179,
		type  =  L_SPOT,
		theta  =  179,
		atten  =  { 1, 0, 0 }
	}
}

If you look closely at the parameters in the lightprops entry, you can see that they look very similar to the values in the D3D8LIGHT8 struct.

A while ago I talked to another Freelancer modder about the lighting bug. After a small investigation they concluded the light type L_SPOT became broken after the Windows update. So they "fixed" it by going into every Thorn script to change each light with the type L_SPOT to L_POINT. Internally this changes the DirectX 8 light type from D3DLIGHT_SPOT to D3DLIGHT_POINT. However, in my opinion this isn't really a good solution because point lights behave very differently from spot lights.

I really wanted to look for a better solution, and based on the clue regarding the redirection of Direct3D8 to the Direct3D9 drivers, I checked out the documentation for the lights from both DirectX 8 and DirectX 9. One thing that stood out to me right away was that the description for the members Falloff, Theta, and Phi simply said "Not supported." in the DirectX 8 documentation, whereas in the DirectX 9 documentation it seems these definitely are supported. In the light specifications from the Thorn scripts I noticed that the value theta was set despite it apparently not even being supported in DirectX 8.

I wanted to find out whether or not the sudden support of the three values in DirectX 9 is the cause of the lighting bug. Though I did not know what the given light values for Falloff or Phi are since they are not specified in the light properties. Hence I decided to use @elishacloud's DirectX-Wrappers project to intercept the IDirect3DDevice8::SetLight method so I could see what the values for each light are and what happens when they are modified.

After some trial and error, I came up with this:

HRESULT m_IDirect3DDevice8::SetLight(DWORD Index, CONST D3DLIGHT8 *pLight)
{
	D3DLIGHT8* pLightEdit = const_cast<D3DLIGHT8*>(pLight);

	// Only the light type D3DLIGHT_SPOT suffers from the lighting bug
	if (pLightEdit->Type == D3DLIGHTTYPE::D3DLIGHT_SPOT)
	{
		// Fix lighting bug
		pLightEdit->Falloff *= 0.5f;
		pLightEdit->Theta *= 0.5f;

		// Impose minimum Falloff to ensure shadows won't look too sharp
		if (pLightEdit->Falloff < 0.6f)
			pLightEdit->Falloff = 0.6f;
	}

	return ProxyInterface->SetLight(Index, pLightEdit);
}

Using the d3d8 wrapper with this code in Freelancer completely rectifies the lighting bug. Basically I reduced the Falloff and Theta values for spot lights to make them appear less harsh. Furthermore, I set a minimum Falloff value to ensure the light edges/shadows look smoother.

I should mention that I can't confirm whether my suspicion about Falloff, Theta, and Phi not working on DirectX 8 is true because I actually haven't done any tests on an older Windows version. Also, with these updated values the lighting doesn't look exactly the same as how it originally did on older Windows versions; in most scenes the light looks slightly dimmer. Maybe a better DirectX programmer can have a look at it one day. Here's the source code for the implemented lighting bug fix as a proof of concept: https://github.com/BC46/freelancer-lighting-bug-fix.

Before and after screenshots:
image
image

@mirh
Copy link

mirh commented Mar 3, 2023

If you have a possible regression range, bisecting with vmware workstation should really be a cakewalk.
You can even go sub-file or sub-version if you have a bit more time.

p.s. for all their bluntness, I think the DXVK people would appreciate you opening a ticket for whatever bug they have (though first I'd hope you tried all the d3d9 compatibility options in dxvk.conf).

@elishacloud
Copy link
Owner

@BC46, thanks for your good research on this! I don't have the game so it is hard for me to test it. But I would like to make a generic fix for this.

One thing that stood out to me right away was that the description for the members Falloff, Theta, and Phi simply said "Not supported." in the DirectX 8 documentation

The documentation that you showed is for Windows CE, it may not be applicable to Windows XP or even Windows 7. Windows CE may be using a cut-down version of DirectX. Also, one thing I have seen in the past is that the DirectX APIs were more forgiving back then. Now Microsoft keeps adding more checks and rejecting API calls that used to work.

If we look at the documentation here we can see that Phi needs to have a number between 0 and Pi (3.14159...) and that Theta cannot be greater than Phi.

What if you change the code to look more like this?:

HRESULT m_IDirect3DDevice8::SetLight(DWORD Index, CONST D3DLIGHT8* pLight)
{
	D3DLIGHT8* pLightEdit = const_cast<D3DLIGHT8*>(pLight);

	//  Fix 'Phi'
	if (pLightEdit->Phi < 0.0f)
	{
		pLightEdit->Phi = 0.0f;
	}
	if (pLightEdit->Phi > M_PI)
	{
		pLightEdit->Phi = M_PI;
	}
	//  Fix 'Theta'
	if (pLightEdit->Theta < 0.0f)
	{
		pLightEdit->Theta = 0.0f;
	}
	if (pLightEdit->Theta > pLightEdit->Phi)
	{
		pLightEdit->Theta = pLightEdit->Phi;
	}

	return ProxyInterface->SetLight(Index, pLightEdit);
}

@elishacloud
Copy link
Owner

elishacloud commented Mar 3, 2023

One more thing you could try is since the documentation claims that Falloff, Theta, and Phi are not supported in DirectX8 you could just try setting them to 0.0f which is the default, according to this site here.

You could also try this one:

HRESULT m_IDirect3DDevice8::SetLight(DWORD Index, CONST D3DLIGHT8* pLight)
{
	D3DLIGHT8* pLightEdit = const_cast<D3DLIGHT8*>(pLight);

	pLightEdit->Falloff = 0.0f;
	pLightEdit->Phi = 0.0f;
	pLightEdit->Theta = 0.0f;

	return ProxyInterface->SetLight(Index, pLightEdit);
}

Edit: this might be the best idea since the code I see on the Internet for d3d8 don't seem to ever set any of these three values and they tend to zero the memory before using:

D3DLIGHT8 light;
ZeroMemory( &light, sizeof(D3DLIGHT8) );

@elishacloud
Copy link
Owner

Here is some good documentation on how this works in DirectX: http://www.directxtutorial.com/Lesson.aspx?lessonid=9-4-9

@elishacloud
Copy link
Owner

So they "fixed" it by going into every Thorn script to change each light with the type L_SPOT to L_POINT. Internally this changes the DirectX 8 light type from D3DLIGHT_SPOT to D3DLIGHT_POINT.

I think this worked because D3DLIGHT_POINT ignores the values of Falloff, Theta, and Phi. The key issue, I think is that the game is sending values for Falloff, Theta, and Phi that are not allowed by DirectX. Thus, the best fix, I think is to fix the values so they are accepted.

I believe this is generic code that should fix this in all cases:

#define _USE_MATH_DEFINES
#include <math.h>

HRESULT m_IDirect3DDevice8::SetLight(DWORD Index, CONST D3DLIGHT8* pLight)
{
	if (!pLight)
	{
		return D3DERR_INVALIDCALL;
	}

	D3DLIGHT8 LightEdit;
	memcpy_s(&LightEdit, sizeof(LightEdit), pLight, sizeof(LightEdit));

	// The maximum allowable value for 'range' is the square root of FLT_MAX.
	static float MaxRange = sqrtf(FLT_MAX);
	if (LightEdit.Range > MaxRange)
	{
		LightEdit.Range = MaxRange;
	}

	switch  (LightEdit.Type)
	{
	case D3DLIGHTTYPE::D3DLIGHT_SPOT:
		// 'Phi' must be between 0 and pi.
		if (LightEdit.Phi < 0.0f)
		{
			LightEdit.Phi = 0.0f;
		}
		if (LightEdit.Phi > M_PI)
		{
			LightEdit.Phi = M_PI;
		}
		//  'Theta' must be in the range from 0 through the value specified by 'Phi'.
		if (LightEdit.Theta < 0.0f)
		{
			LightEdit.Theta = 0.0f;
		}
		if (LightEdit.Theta > LightEdit.Phi)
		{
			LightEdit.Theta = LightEdit.Phi;
		}
		// 'Falloff' a falloff other than 1.0 takes time to process, developers usually use 1.0
		LightEdit.Falloff = 1.0f;
		break;
	case D3DLIGHTTYPE::D3DLIGHT_DIRECTIONAL:
		LightEdit.Range = 0.0f;		// This member does not affect directional lights.
		__fallthrough;
	case D3DLIGHTTYPE::D3DLIGHT_POINT:
		LightEdit.Falloff = 0.0f;
		LightEdit.Phi = 0.0f;
		LightEdit.Theta = 0.0f;
		break;
	default:
		return D3DERR_INVALIDCALL;
	}

	return ProxyInterface->SetLight(Index, &LightEdit);
}

Please let me know if this works.

@BC46
Copy link
Contributor Author

BC46 commented Mar 3, 2023

Thank you for the links and the code snippets @elishacloud!

With the first and third snippet the lighting bug was still present in the game unfortunately; same result as this:
bug

The second one made all the objects either black or very dark:
image

Would it be helpful if I sent a collection of D3DLIGHT8 instances that DirectX receives from the game during this particular scene? Maybe that will allow you to spot any peculiar values if there are any.

@elishacloud
Copy link
Owner

Would it be helpful if I sent a collection of D3DLIGHT8 instances that DirectX receives from the game during this particular scene?

Yes, this would be helpful. Thanks!

@BC46
Copy link
Contributor Author

BC46 commented Mar 3, 2023

I hope the logging format is a bit clear: d3dlight8_log.txt.

@elishacloud
Copy link
Owner

elishacloud commented Mar 3, 2023

Thanks for the logs! It seems like in almost every case (except index 4) it sets Theta and Phi to the same value. In this case it sounds like d3d9 is working correctly. It should show sharp contrast (like the undesirable graphic above) rather than a gradient change. See the "Phi and Theta" section from this page.

FallOff is always set to 1, which is the normal value, so we should not need to change that at all.

I think what might be happening is that older versions of DirectX used to treat it differently when Theta and Phi had the same value. In this case, to simulate how the older DirectX used to work we may be able to just set Theta to 0 when Theta and Phi have the same value.

We can try something like this:

HRESULT m_IDirect3DDevice8::SetLight(DWORD Index, CONST D3DLIGHT8* pLight)
{
	if (!pLight)
	{
		return D3DERR_INVALIDCALL;
	}

	D3DLIGHT8 LightEdit;
	memcpy_s(&LightEdit, sizeof(LightEdit), pLight, sizeof(LightEdit));

	if (LightEdit.Type == D3DLIGHTTYPE::D3DLIGHT_SPOT)
	{
		if (LightEdit.Phi == LightEdit.Theta)
		{
			LightEdit.Theta = 0.0f;
		}
	}

	return ProxyInterface->SetLight(Index, &LightEdit);
}

Another idea is that after looking at the LUA:

{
	entity_name  =  "ambi_LtG03_Basement_Ohd_Ylw",
	type  =  LIGHT,
	template_name  =  "",
	lt_grp  =  3, srt_grp  =  0, usr_flg  =  0,
	spatialprops  = 
	{
		pos  =  { -5.010058, 0, 1.758013 },
		orient  =  { { -0.105263, -0.008535, -0.994408 },
				   { 0.977260, 0.184208, -0.105029 },
				   { 0.184075, -0.982850, -0.011049 } }
	},
	lightprops  = 
	{
		on  =  Y,
		color  =  { 234, 192, 115 },
		diffuse  =  { 0.623529, 0.576471, 0.376471 },
		specular  =  { 0, 0, 0 },
		ambient  =  { 0.086275, 0.086275, 0.07451 },
		direction  =  { 0, 0, 1 },
		range  =  100,
		cutoff  =  179,
		type  =  L_SPOT,
		theta  =  179,
		atten  =  { 1, 0, 0 }
	}
}

I noticed that "cutoff" and "theta" are the same value. I guess that one of them affects Theta and the other one affects Phi. Maybe if you changed one of these values to "0" it would also solve the issue. Presumably, you would want to set "cutoff" to 0.

@BC46
Copy link
Contributor Author

BC46 commented Mar 4, 2023

Yes, that one did the trick. Thanks a lot!

Lighting fix:
image

Original (legacy d3d8.dll):
image

Slightly dimmer than what it looks like with the legacy d3d8.dll, but overall still a great result!

As for the Lua script, setting theta to 0 for lights with the L_SPOT type indeed worked as well. Though I still prefer the DirectX call intercept approach since this way I can programmatically check if the lighting bug would be present on the user's system. Based on that I can determine whether or not the fix should be applied. Also saves me the hassle of having to modify every single Lua script. 😃

@elishacloud
Copy link
Owner

elishacloud commented Mar 4, 2023

Thanks for testing this!

To solve the issue where the lighting is darker than the legacy d3d8.dll, I suspect you could just double the FallOff. However, I want to try and isolate the issue with the legacy d3d8.dll as much as possible to ensure we can match the functionality.

If you would be willing to try some tests with the legacy d3d8.dll I would be grateful. I want to see if this only happens when both the Theta and Phi are set the exact same. In the LUA script if you change the theta to be only slightly smaller than the Phi does the picture still look good in the legacy d3d8.dll or does that mess up the lighting, like it does with the newer d3d8.dll files?

Edit: Also, when you use the Lua script to set theta to 0 for lights with the L_SPOT type, can you test this with the legacy d3d8.dll? I want to see if this makes the legacy d3d8.dll and the newer d3d8.dll appear the same in the game.

@BC46
Copy link
Contributor Author

BC46 commented Mar 4, 2023

In the LUA script if you change the theta to be only slightly smaller than the Phi does the picture still look good in the legacy d3d8.dll or does that mess up the lighting, like it does with the newer d3d8.dll files?

For all L_SPOT lights I set theta to its cutoff value minus 2. E.g. one light has cutoff = 30 and theta = 28 (I'm assuming cutoff controls Phi). Loading this scene with the legacy d3d8.dll made pretty much no difference; the lighting still looks good.

Also, when you use the Lua script to set theta to 0 for lights with the L_SPOT type, can you test this with the legacy d3d8.dll? I want to see if this makes the legacy d3d8.dll and the newer d3d8.dll appear the same in the game.

Setting theta = 0 for all L_SPOT lights and loading the scene with the legacy d3d8.dll indeed makes the lights look the same as if they were rendered using the newer d3d8.dll.

image

@elishacloud
Copy link
Owner

one light has cutoff = 30 and theta = 28 (I'm assuming cutoff controls Phi). Loading this scene with the legacy d3d8.dll made pretty much no difference; the lighting still looks good.

Ok, this is what I was afraid of. I believe Theta works differently in the legacy then it does in the new driver.

Try this one and see if it makes the newer d3d8.dll look more like the legacy one:

HRESULT STDMETHODCALLTYPE Direct3DDevice8::SetLight(DWORD Index, const D3DLIGHT8 *pLight)
{
	if (!pLight)
	{
		return D3DERR_INVALIDCALL;
	}

	D3DLIGHT8 LightEdit;
	memcpy_s(&LightEdit, sizeof(LightEdit), pLight, sizeof(LightEdit));

	if (LightEdit.Type == D3DLIGHTTYPE::D3DLIGHT_SPOT)
	{
		if (LightEdit.Phi >= LightEdit.Theta)
		{
			LightEdit.Theta = 0.0f;
			LightEdit.Falloff = LightEdit.Falloff * (1.0f + (LightEdit.Theta / LightEdit.Phi));
		}
	}

	return ProxyInterface->SetLight(Index, &LightEdit);
}

@BC46
Copy link
Contributor Author

BC46 commented Mar 10, 2023

Can you send me a Microsoft PIX output file of that frame?

Do I have to load the scene with the 16x AF and 8x AA enabled from d3d8?

@elishacloud
Copy link
Owner

You could enable AF and AA from d3d8 if you like. Then you can use d3d8to9 to covert that to d3d9. I do plan to look at the code and see if I can see any issues with dxwrapper's AF that could cause this issue.

@BC46
Copy link
Contributor Author

BC46 commented Mar 14, 2023

Sorry for the delay but I'm currently very busy studying for an upcoming exam. I'll provide the PIX files as soon as I can.

@BC46
Copy link
Contributor Author

BC46 commented Mar 18, 2023

I just tried making a GPU capture with PIX while Freelancer is running. Unfortunately it didn't work because the game is x86 and PIX only supports x64 apps from what I could find. Is there anything else I can try?

@elishacloud
Copy link
Owner

elishacloud commented Mar 18, 2023

Yeah, you need the old version of PIX. The new one doesn't work on DirectX9 or 32-bit applications.

You need to download the old June 2010 SDK. Then you should be able to find the old version of PIX there. See this site.

Once I installed the June 2010 SDK I found PIX here:

C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Utilities\bin\x86\PIXWin.exe

@BC46
Copy link
Contributor Author

BC46 commented Mar 19, 2023

Here they are: PIX.zip. Both captures were made with AF and AA enabled from DxWrapper. The RX5700-DxWrapper.PIXRun file was taken on my main rig with the AMD RX 5700 (detail and emission textures were visible). The GTX1050-DxWrapper.PIXRun file I took on my old laptop with the GTX 1050 GPU (detail and emission textures were not visible).

@elishacloud
Copy link
Owner

Basically Freelancer uses so-called "detail textures" which are grayscale textures that are mapped on top of regular textures to make those appear more detailed.
Also notice how in the second image the ship's lights on the top right appear to be turned off. This is because the emission map for it failed to load.

In both of these cases the game is using texture stage 1 to draw these items. As far as I can tell there are only a few things that are drawn by this game using stage 1.

The weird thing is that in the GTX capture these function calls were completely missing. I am not sure what could cause these calls to be completely missing. It is almost like something caused the game to decide not to do any stage 1 function calls.

Because recently as a test I force-enabled 16x AF and 8x AA in Freelancer using the d3d8 wrapper, and that worked like a charm without any repercussions.

What wrapper did you use to force 16x AF? How exactly did you use the wrapper to force this?

@elishacloud
Copy link
Owner

You could try this update, I'm not sure it will help, but it is worth a try; dxwrapper.zip

@BC46
Copy link
Contributor Author

BC46 commented Mar 22, 2023

What wrapper did you use to force 16x AF? How exactly did you use the wrapper to force this?

I used the d3d8 wrapper from your DirectX Wrappers project. As for the 16x AF, I simply updated the m_IDirect3DDevice8::SetTextureStageState method so it looks like this:

HRESULT m_IDirect3DDevice8::SetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value)
{
	if (Type == D3DTSS_MAGFILTER)
		Value = D3DTEXF_ANISOTROPIC;
	if (Type == D3DTSS_MINFILTER)
		Value = D3DTEXF_ANISOTROPIC;
	if (Type == D3DTSS_MIPFILTER)
		Value = D3DTEXF_ANISOTROPIC;
	if (Type == D3DTSS_MAXANISOTROPY)
		Value = 16;

	return ProxyInterface->SetTextureStageState(Stage, Type, Value);
}

I know you're not supposed to force-enable AF this way, but I just did it as a test.

You could try this update, I'm not sure it will help, but it is worth a try; dxwrapper.zip

With this build the textures do seem to load on the GTX PC. Well done! However, I just noticed that the AF doesn't seem to be working (this is also the case with the previous DxWrapper build):
Untitled

On the AMD PC it works without issues:
image

@elishacloud
Copy link
Owner

With this build the textures do seem to load on the GTX PC. Well done! However, I just noticed that the AF doesn't seem to be working (this is also the case with the previous DxWrapper build):

Ok, this means that the GTX you have does not support multi-staged AF textures. I made a simple change to turn off AF if multi-staged AF was not supported. I'm not sure the best way to turn off AF only when actually drawing multi-staged textures.

@elishacloud
Copy link
Owner

elishacloud commented Mar 22, 2023

Ok, try this one. I have it disable AF only when a multi-stage texture is actually set. dxwrapper.zip

@BC46
Copy link
Contributor Author

BC46 commented Mar 22, 2023

Same result as with the last build. Could have something to do with the GPU.

@elishacloud
Copy link
Owner

Ok, can you try with one more update? dxwrapper.zip

Also, please upload your log files for both systems.

@BC46
Copy link
Contributor Author

BC46 commented Mar 22, 2023

Unfortunately still no AF on the GTX 1050 laptop as far as I could tell. Here are the logs:
dxwrapper-freelancer-1050.log
dxwrapper-freelancer-5700.log

@elishacloud
Copy link
Owner

Ok, I think this is the best we can get: dxwrapper.zip

Can you try this one and let me know how it works on both systems? Does AF work? Are there any missing textures? Etc.

Thanks for your help here!

@BC46
Copy link
Contributor Author

BC46 commented Mar 22, 2023

Alright, so on the RX 5700 PC all the textures loaded just fine, AA and AF both worked (same result as with the previous builds). On the GTX 1050 laptop however, the detail and emission textures appeared to be invisible again, as opposed to the last three builds. AA seemed to work fine though, but not AF.

@elishacloud
Copy link
Owner

Ok, that is not what I expected. I don't think there is anyway I can get the GTX 1050 to work with AF and support those textures on d3d9.

Try one more build. I hope this is the last: dxwrapper.zip

@BC46
Copy link
Contributor Author

BC46 commented Mar 23, 2023

With this build the emission and detail textures didn't work on the GTX 1050, neither did AF. Additionally, this time the AF option stopped working on the RX 5700 as well.

I don't think there is anyway I can get the GTX 1050 to work with AF and support those textures on d3d9.

Oh well, at least the detail and emission textures can be loaded, so that's definitely an improvement!

@elishacloud
Copy link
Owner

elishacloud commented Mar 23, 2023

Too bad! I was hoping I would not need to make this more complicated. Ok, thanks for trying all these. I hope this one works correctly. It is similar to the second one I gave you.

Can you try this one: dxwrapper.zip

Note: the issue here is that I need to account for cube and volume textures, which makes it more complex. The first testing ones I gave you did not account for that.

@BC46
Copy link
Contributor Author

BC46 commented Mar 23, 2023

Alright, this is an interesting one. With the RX 5700, everything works fine. On the GTX 1050 however, the detail and emission textures seem to load at first, but after Alt-Tabbing and reloading the scene, they're no longer there. I didn't notice this behavior with the second build.

Edit:
It's possible AF has been working on the GTX 1050 all along, just at a very low sample rate.

@elishacloud
Copy link
Owner

after Alt-Tabbing and reloading the scene, they're no longer there. I didn't notice this behavior with the second build.

Ok, I was just thinking I might need to reset it. Try this one to see if this is fixed: dxwrapper.zip

It's possible AF has been working on the GTX 1050 all along, just at a very low sample rate.

From the logs it looks like the GTX supports multi-stage AF for MinFiltering but not for MagFiltering. This could be why it looks like it is very low sample rate.

@BC46
Copy link
Contributor Author

BC46 commented Mar 23, 2023

Great, the issue has been fixed with the newest build. Tested it on both the RX 5700 and GTX 1050; couldn't find any new issues.

@elishacloud
Copy link
Owner

Ok, here is the final build. I integrated all the fixes in. If you don't mind testing one last time I would be grateful: dxwrapper.zip

@BC46
Copy link
Contributor Author

BC46 commented Mar 23, 2023

Of course! Seems to work ok on both systems.

@elishacloud
Copy link
Owner

Great! Thanks for all your help here!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants