AMD - Anisotropic filtering with nearest point filtering not working properly?

Started by
11 comments, last by Norman Barrows 8 years, 1 month ago

I just recently started to work/experiment low-level DirectX access in my current project (DirectX 9.0) .
I want the textures to have a crisp look to it, so i render them with Point filtering. But in order to make textures look good over distance, i enabled Anisotropic filtering.
The code looks like this:


//anisotropic filtering
d3ddev->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_ANISOTROPIC);
d3ddev->SetSamplerState(0,D3DSAMP_MAXANISOTROPY,8);

//nearest point filtering
d3ddev->SetSamplerState(0,D3DSAMP_MIPFILTER,D3DTEXF_POINT);
d3ddev->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_POINT);

Now, on all my Nvidia GPUs and IntelHD Chipsets (like the IntelHD 4000 in my laptop) all of this works as intended and looks like this:
[spoiler]texturefilter_point.png[/spoiler]

Now, i was also able to test this on an AMD Rig with a Ati Radeon HD 7950. And this is the result:
[spoiler]texturefilter_linear.png[/spoiler]
No matter what i do, nearest point filtering doesn't want to work. (It seems to revert back to linear filtering...) I also tested this on a friends PC which also had the same GPU (Radeon HD 7950). Same issue here. Both PCs had up to date AMD drivers.

/Edit: Also tested on a Radeon HD 7850... same issue here.


Now my question is: is this a driver issue? If so, how can i bypass that? (The simplest solution would be to upscale the texture to a higher resolution in order to reduce the effect, but this is a very dirty and unsatisfying solution IMHO.)

I was able to find a topic on the Ogre forums which describes a similar issue (back from 2013) where the members also suspect a driver issue:
http://www.ogre3d.org/forums/viewtopic.php?f=4&t=77217

Does anyone have information about that? Is this a known driver issue?

/edit: Note that i'm a total noob when it comes to this low level stuff (just starting out.) Maybe i'm overlooking something?

/Edit2: Just noticed that i posted this in the wrong forum sub-category... oh well...

Advertisement
From memory, it's a requirement that min/mag must both be set to aniso, and that setting only one of them should actually be an API error.

Do your textures have mipmaps already? They're key to making distant textures look good (and also perform adequately!)

You could use something like iq's quintic curve to make filtered textures look pixely if thats what you're after.

From memory, it's a requirement that min/mag must both be set to aniso, and that setting only one of them should actually be an API error.

Do your textures have mipmaps already? They're key to making distant textures look good (and also perform adequately!)

You could use something like iq's quintic curve to make filtered textures look pixely if thats what you're after.

If i set both min and mag to aniso, the texture filtering becomes linear instead of nearest point:


//anisotropic filtering
d3ddev->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_ANISOTROPIC);
d3ddev->SetSamplerState(0,D3DSAMP_MAXANISOTROPY,8);
d3ddev->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_ANISOTROPIC);

//nearest point filtering
d3ddev->SetSamplerState(0,D3DSAMP_MIPFILTER,D3DTEXF_POINT); //Shouldn't the magfilter do the actual point sampling for the desired effect?
//As far as my understanding goes the Mipfilter is responsible for the mipmapping but not directly for the final look of the texture.
//That would explain why the texture is rendered in a similar way to linear filtering.

I didn't generate any mimpamps manually (the issue here is that i don't really have direct access to the underlying directX calls of the engine. So everything i do here is pretty much "hacked in" by manually calling the DirectX calls via a DLL in between draw-calls.)

As i said, it works fine on Nvidia and Intel chipsets. But on AMD it doesn't.

Are the samplerstate calls even correct? (Don't have experience in it.) What i basically want are pixel perfect Textures (nearest point filtering) when up close but avoid any kind of shimmering/artifacting on longer distances (thus having anisotropic filtering enabled.)

I'll also look at the link you provided.

And btw, thanks for moving the topic to the DirectX subforum.

/Edit:

According to that link:

https://msdn.microsoft.com/en-us/library/windows/desktop/bb322811%28v=vs.85%29.aspx

Anisotropic filtering can be either a magnification OR minifaction filter. So i suppose the original code is alright?

As far as I know there is no such thing as "point anistropic" filtering. Anisotropic, by definition, requires performing many taps; which is orthogonal with the notion of point filtering. Have you compared the difference between regular point filtering and what you see as "point anistropic"?. As Hodgman said it is an error not to set both mag and min to anisotropic.

Edit: I missread your post. You set Min to Aniso, and Mag to Point filtering. I thought you had set Mip to aniso (which is undefined behavior). I don't know if the specs allow what you're doing or not.

Edit 2: Check the driver isn't configured to override filtering, which is a common option (i.e. high quality vs high performance vs balanced, etc).

As far as I know there is no such thing as "point anistropic" filtering. Anisotropic, by definition, requires performing many taps; which is orthogonal with the notion of point filtering. Have you compared the difference between regular point filtering and what you see as "point anistropic"?. As Hodgman said it is an error not to set both mag and min to anisotropic.

Edit: I missread your post. You set Min to Aniso, and Mag to Point filtering. I thought you had set Mip to aniso (which is undefined behavior). I don't know if the specs allow what you're doing or not.

Edit 2: Check the driver isn't configured to override filtering, which is a common option (i.e. high quality vs high performance vs balanced, etc).

I checked the driver and i didn't see anything that could overwrite the filtering options. (I'll check a second time just to make sure.)

Also another tester reported that this is also happening on his Radeon R9 270X...

How does your game look if you use linear instead of aniso for the min filter?

If i set both min and mag to aniso, the texture filtering becomes linear instead of nearest point

Exactly. My memory of D3D9 is that aniso had to be set for both, and aniso is an extension of linear filtering, so, it's not valid to combine point-filtering and anisotropy.
In D3D11 they changed the texture filtering API completely so that this is now forced upon you.
e.g. they have enum values that set min/mag/mip all at once, one for every possible combination -- such as D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT sets min to linear, and mag/mip to point.
However, aniso only gets a single entry -- D3D11_FILTER_ANISOTROPIC -- which enables anisotropic min/mag filtering and linear mip filtering.
So this mag=linear+min=aniso setting that you're using on NVidia/Intel isn't actually possible any more via D3D11 ohmy.png

Are the samplerstate calls even correct?

Check whether they're returning D3D_OK or D3DERR_INVALIDCALL.

Maybe also call IDirect3D9::GetDeviceCaps and see what the TextureFilterCaps are for these AMD cards.

How does your game look if you use linear instead of aniso for the min filter?

Made 2 screenshots. (Both on my nvidia GPU)

Minfilter: linear, Magfilter: linear, Mipfilter: nearest point:

[spoiler]filter_test_magfilter_linear.png[/spoiler]

Minfilter: linear, Magfilter: nearest point, Mipfilter: nearest point:

[spoiler]filter_test_Magfilter_point.png[/spoiler]

/edit:

That's how it looks like (and how i would like it to look like) with minfilter as aniso and magfilter as nearest point: (But this doesn't work on ATI/AMD)

[spoiler]texture_filter_test_aniso_and_point.png[/spoiler]

If i set both min and mag to aniso, the texture filtering becomes linear instead of nearest point

Exactly. My memory of D3D9 is that aniso had to be set for both, and aniso is an extension of linear filtering, so, it's not valid to combine point-filtering and anisotropy.
In D3D11 they changed the texture filtering API completely so that this is now forced upon you.
e.g. they have enum values that set min/mag/mip all at once, one for every possible combination -- such as D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT sets min to linear, and mag/mip to point.
However, aniso only gets a single entry -- D3D11_FILTER_ANISOTROPIC -- which enables anisotropic min/mag filtering and linear mip filtering.
So this mag=linear+min=aniso setting that you're using on NVidia/Intel isn't actually possible any more via D3D11 ohmy.png

Ah, ok. But if that's not possible, how would one go about implementing such an effect? Surely someone on earth already wanted to implement something like this. (Every game which wants to have a "crisp" pixel look but not have bad texturequality over distance.)

Check whether they're returning D3D_OK or D3DERR_INVALIDCALL.

Maybe also call IDirect3D9::GetDeviceCaps and see what the TextureFilterCaps are for these AMD cards.

I'll check that as soon as possible.


Minfilter: linear, Magfilter: linear, Mipfilter: nearest point:
You could try setting D3DSAMP_MIPMAPLODBIAS to -1 or -2, etc -- this will push the distances at which it switches to each mipmap level (the obvious sudden change to blurry textures) back into a distance a bit.

As i said, it works fine on Nvidia and Intel chipsets. But on AMD it doesn't.


Just as a minor point and to reinforce something Hodgman said - just because it works as expected somewhere doesn't mean it is 'right'.

I have found in the past, typically with OpenGL, that when it comes to implementation AMD tend to stick closer to the letter of the spec, where NV take a more 'whatever works' approach. This can mean that NV will let things go where AMD will throw up errors or do what you don't expect - annoying but there it is :|
if you stumble on places where behavior diverges, it's best to enable D3D-Debug.

It's sadly true that anisotropic filtering is implemented as an extension of linear filtering, although these are orthogonal. Anisotropic is to overcome distorted texture projections, hence makes the same sense for point as it does for bi-linear. You wouldn't distinguish linear vs anisotropic on a surface that is facing straight at you.

One way to implement your effect is to setup the texture twice, with anisotropic and point, sample twice in the shader and blend between boths.
you can implement blending either by evaluating max(ddx(uv),ddy(uv)) or if the alpha channel of your texture is spare, set the first mip-alpha to white, all other mips-alpha to black.
kinda

float4 CLinear = tex2d(tex0,uv);
float4 CPoint = tex2d(tex0,uv);
float3 C = lerp(CLinear.rgb,CPoint.rgb,Linear.a);

This topic is closed to new replies.

Advertisement