<p>The texture filtering hardware takes several samples of the various mipmap levels (the maximum amount of samples is indicated by the anisotropic filtering level, though the exact amount of samples taken in a given filtering operation will depend on the proportion between the derivatives on the fragment.) If you project the cone viewing a surface at an oblique angle onto the texture space, it will result in approximately an oval shaped projection, which is more elongated for more oblique angles. Extra samples are taken along the axis of this oval (from the correct mip levels, to take advantage of the pre-filtering they offer) and combined to give a sharper texture sample.</p>

<p>Another technique know as <a href="https://en.wikipedia.org/wiki/Mipmap" rel="noreferrer">rip-mapping</a> (mentioned in the Wikipedia article on Mipmapping), which is <em>not</em> commonly found in contemporary GPUs, uses prefiltering of textures. In contrast to mips, the texture is not scaled down uniformly but using various height-width-ratios (up to a ratio dependent on your chosen anisotropic filtering level). The variant - or maybe two variants if using trilinear filtering - of the texture is then chosen based on the angle of the surface to minimize distortion. Pixel values are fetched using default filtering techniques (bilinear or trilinear). Rip-maps are not used in any hardware that I know of due to their prohibitive size: while mipmaps use additional 33% storage, ripmaps use 300%. This can be verified by noting that texture usage requirements don't increase when using AF, rather, only bandwidth does.</p>

<p>For futher reading, you might want to take a look at the specification for the <a href="https://www.opengl.org/registry/specs/EXT/texture_filter_anisotropic.txt" rel="noreferrer">EXT_texture_filter_anisotropic</a> OpenGL extension. It details the formulas used to calculate samples and how to combine them when using anisotropic filtering.</p>

CC BY-SA 3.0
2015-09-04T09:43:19.890Z
RIP maps also probably aren't used because they don't help on the, rather common, diagonal case.

FWIW, if you can find the code for the Microsoft Refrast, the anistropic filter implementation in that is probably a good reference for how today's HW does it.
Simon F
CC BY-SA 3.0
2015-09-04T10:22:07.030Z
"This can be verified by noting that texture usage requirements don't increase when using AF, rather, only bandwidth does." Killer argument. Good answer!
David Kuri
CC BY-SA 3.0
2015-09-09T18:30:27.923Z
The "High-Performance Software Rasterization on GPUs" link only mentions anisotropic filtering in passing once, and gives no mention of any details. So I'm going to edit it out of the answer because I don't think it's relevant in a helpful way.
yuriks
CC BY-SA 3.0
2015-09-11T02:06:37.223Z
@SimonF also we can add that the additional bandwidth requirement is pretty scary.
v.oddou
CC BY-SA 3.0
2015-09-04T09:18:52.440Z
2015-09-09T18:33:28.380Z
2015-09-09T18:33:28.380Z
yuriks
<p>The API requirements can be found in any of the specs or extensions. Here is one: <a href="https://www.opengl.org/registry/specs/EXT/texture_filter_anisotropic.txt">https://www.opengl.org/registry/specs/EXT/texture_filter_anisotropic.txt</a></p>

<p>All GPU vendors likely deviate from the spec because AF-quality used to be a part of many benchmarks. And current implementations will continue to keep on evolving as new workloads stress the existing approximations. Unfortunately, to know exactly what either does, you will need to be a part of one of the companies. But you can gauge the spectrum of possibilities from the following papers, listed in increasing order of quality and implementation cost:</p>

<ul>
<li><a href="http://www.researchgate.net/publication/3208533_Texram_a_smart_memory_for_texturing">TexRam</a></li>
<li><a href="http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-99-1.pdf">FELINE</a></li>
<li><a href="http://ieeexplore.ieee.org/xpls/abs_all.jsp?arnumber=4056910&amp;tag=1">EWA</a></li>
</ul>

<p>Quoting from the spec:</p>

<pre><code> Anisotropic texture filtering substantially changes Section 3.8.5.
 Previously a single scale factor P was determined based on the
 pixel's projection into texture space.  Now two scale factors,
 Px and Py, are computed.

   Px = sqrt(dudx^2 + dvdx^2)
   Py = sqrt(dudy^2 + dvdy^2)

   Pmax = max(Px,Py)
   Pmin = min(Px,Py)

   N = min(ceil(Pmax/Pmin),maxAniso)
   Lamda' = log2(Pmax/N)

 where maxAniso is the smaller of the texture's value of
 TEXTURE_MAX_ANISOTROPY_EXT or the implementation-defined value of
 MAX_TEXTURE_MAX_ANISOTROPY_EXT.

 It is acceptable for implementation to round 'N' up to the nearest
 supported sampling rate.  For example an implementation may only
 support power-of-two sampling rates.

 It is also acceptable for an implementation to approximate the ideal
 functions Px and Py with functions Fx and Fy subject to the following
 conditions:

   1.  Fx is continuous and monotonically increasing in |du/dx| and |dv/dx|.
       Fy is continuous and monotonically increasing in |du/dy| and |dv/dy|.

   2.  max(|du/dx|,|dv/dx|} &lt;= Fx &lt;= |du/dx| + |dv/dx|.
       max(|du/dy|,|dv/dy|} &lt;= Fy &lt;= |du/dy| + |dv/dy|.

 Instead of a single sample, Tau, at (u,v,Lamda), 'N' locations in the mipmap
 at LOD Lamda, are sampled within the texture footprint of the pixel.

 Instead of a single sample, Tau, at (u,v,lambda), 'N' locations in
 the mipmap at LOD Lamda are sampled within the texture footprint of
 the pixel.  This sum TauAniso is defined using the single sample Tau.
 When the texture's value of TEXTURE_MAX_ANISOTROPHY_EXT is greater
 than 1.0, use TauAniso instead of Tau to determine the fragment's
 texture value.

                i=N
                ---
 TauAniso = 1/N \ Tau(u(x - 1/2 + i/(N+1), y), v(x - 1/2 + i/(N+1), y)),  Px &gt; Py
                /
                ---
                i=1

                i=N
                ---
 TauAniso = 1/N \ Tau(u(x, y - 1/2 + i/(N+1)), v(x, y - 1/2 + i/(N+1))),  Py &gt;= Px
                /
                ---
                i=1


 It is acceptable to approximate the u and v functions with equally spaced
 samples in texture space at LOD Lamda:

                i=N
                ---
 TauAniso = 1/N \ Tau(u(x,y)+dudx(i/(N+1)-1/2), v(x,y)+dvdx(i/(N+1)-1/2)), Px &gt; Py
                /
                ---
                i=1

                i=N
                ---
 TauAniso = 1/N \ Tau(u(x,y)+dudy(i/(N+1)-1/2), v(x,y)+dvdy(i/(N+1)-1/2)), Py &gt;= Px
                /
                ---
                i=1 
</code></pre>

CC BY-SA 3.0
2015-09-04T21:38:10.823Z
2015-09-04T21:38:10.823Z
ap_
<p><a href="https://en.wikipedia.org/wiki/Anisotropic_filtering">Anisotropic filtering</a> "retains the sharpness of a texture normally lost by MIP map texture's attempts to avoid aliasing". The Wikipedia article gives hints about how it can be implemented ("probe the texture (...) for any orientation of anisotropy"), but it does't read very clear to me.  </p>

<p>There seem to be various implementations, as suggested by the tests illustrated in the <a href="https://dl.dropboxusercontent.com/u/6809780/BLOG_HOSTING/sig2015_approx_models_PBR_notes_DRAFT.pdf">notes</a> of the presentation <a href="http://c0de517e.blogspot.jp/2016/07/siggraph-2015-notes-for-approximate.html">Approximate Models For Physically Based Rendering</a>:
<a href="https://dl.dropboxusercontent.com/u/6809780/BLOG_HOSTING/sig2015_approx_models_PBR_notes_DRAFT.pdf#page=37"><img src="https://i.sstatic.net/9NAa0.png" alt="enter image description here"></a></p>

<p>What are the concrete computations performed by (modern) GPUs to choose the correct MIP level when using anisotropic filtering?</p>

CC BY-SA 3.0
2015-09-04T20:39:03.017Z
The spec for [`GL_EXT_texture_filter_anisotropic`](https://www.opengl.org/registry/specs/EXT/texture_filter_anisotropic.txt) is very detailed. Maybe it might help you better understand the process.
glampert
<texture><gpu><algorithm><implementation>
How is anisotropic filtering typically implemented in modern GPUs?
wip
# How is anisotropic filtering typically implemented in modern GPUs?

(Asked by: username_0 on 2015-09-04)

[Anisotropic filtering](https://en.wikipedia.org/wiki/Anisotropic_filtering) "retains the sharpness of a texture normally lost by MIP map texture's attempts to avoid aliasing". The Wikipedia article gives hints about how it can be implemented ("probe the texture (...) for any orientation of anisotropy"), but it does't read very clear to me.

There seem to be various implementations, as suggested by the tests illustrated in the [notes](https://dl.dropboxusercontent.com/u/6809780/BLOG_HOSTING/sig2015_approx_models_PBR_notes_DRAFT.pdf) of the presentation [Approximate Models For Physically Based Rendering](http://c0de517e.blogspot.jp/2016/07/siggraph-2015-notes-for-approximate.html):
[![enter image description here](https://i.sstatic.net/9NAa0.png)](https://dl.dropboxusercontent.com/u/6809780/BLOG_HOSTING/sig2015_approx_models_PBR_notes_DRAFT.pdf#page=37)

What are the concrete computations performed by (modern) GPUs to choose the correct MIP level when using anisotropic filtering?

**Tags:** texture, gpu, algorithm, implementation

> **Comments:**
> **username_1**: The spec for [`GL_EXT_texture_filter_anisotropic`](https://www.opengl.org/registry/specs/EXT/texture_filter_anisotropic.txt) is very detailed. Maybe it might help you better understand the process.  

---

## 2 answers

### Answer by username_2 on 2015-09-04. Score: 17

The texture filtering hardware takes several samples of the various mipmap levels (the maximum amount of samples is indicated by the anisotropic filtering level, though the exact amount of samples taken in a given filtering operation will depend on the proportion between the derivatives on the fragment.) If you project the cone viewing a surface at an oblique angle onto the texture space, it will result in approximately an oval shaped projection, which is more elongated for more oblique angles. Extra samples are taken along the axis of this oval (from the correct mip levels, to take advantage of the pre-filtering they offer) and combined to give a sharper texture sample.

Another technique know as [rip-mapping](https://en.wikipedia.org/wiki/Mipmap) (mentioned in the Wikipedia article on Mipmapping), which is *not* commonly found in contemporary GPUs, uses prefiltering of textures. In contrast to mips, the texture is not scaled down uniformly but using various height-width-ratios (up to a ratio dependent on your chosen anisotropic filtering level). The variant - or maybe two variants if using trilinear filtering - of the texture is then chosen based on the angle of the surface to minimize distortion. Pixel values are fetched using default filtering techniques (bilinear or trilinear). Rip-maps are not used in any hardware that I know of due to their prohibitive size: while mipmaps use additional 33% storage, ripmaps use 300%. This can be verified by noting that texture usage requirements don't increase when using AF, rather, only bandwidth does.

For futher reading, you might want to take a look at the specification for the [EXT\_texture\_filter\_anisotropic](https://www.opengl.org/registry/specs/EXT/texture_filter_anisotropic.txt) OpenGL extension. It details the formulas used to calculate samples and how to combine them when using anisotropic filtering.

> **Comments:**
> **username_3**: RIP maps also probably aren't used because they don't help on the, rather common, diagonal case.  FWIW, if you can find the code for the Microsoft Refrast, the anistropic filter implementation in that is probably a good reference for how today's HW does it.  
> **username_4**: "This can be verified by noting that texture usage requirements don't increase when using AF, rather, only bandwidth does." Killer argument. Good answer!  
> **username_2**: The "High-Performance Software Rasterization on GPUs" link only mentions anisotropic filtering in passing once, and gives no mention of any details. So I'm going to edit it out of the answer because I don't think it's relevant in a helpful way.  
> **username_5**: @username_3 also we can add that the additional bandwidth requirement is pretty scary.  

---

### Answer by username_6 on 2015-09-04. Score: 9

The API requirements can be found in any of the specs or extensions. Here is one: <https://www.opengl.org/registry/specs/EXT/texture_filter_anisotropic.txt>

All GPU vendors likely deviate from the spec because AF-quality used to be a part of many benchmarks. And current implementations will continue to keep on evolving as new workloads stress the existing approximations. Unfortunately, to know exactly what either does, you will need to be a part of one of the companies. But you can gauge the spectrum of possibilities from the following papers, listed in increasing order of quality and implementation cost:

* [TexRam](http://www.researchgate.net/publication/3208533_Texram_a_smart_memory_for_texturing)
* [FELINE](http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-99-1.pdf)
* [EWA](http://ieeexplore.ieee.org/xpls/abs_all.jsp?arnumber=4056910&tag=1)

Quoting from the spec:

```
 Anisotropic texture filtering substantially changes Section 3.8.5.
 Previously a single scale factor P was determined based on the
 pixel's projection into texture space.  Now two scale factors,
 Px and Py, are computed.

   Px = sqrt(dudx^2 + dvdx^2)
   Py = sqrt(dudy^2 + dvdy^2)

   Pmax = max(Px,Py)
   Pmin = min(Px,Py)

   N = min(ceil(Pmax/Pmin),maxAniso)
   Lamda' = log2(Pmax/N)

 where maxAniso is the smaller of the texture's value of
 TEXTURE_MAX_ANISOTROPY_EXT or the implementation-defined value of
 MAX_TEXTURE_MAX_ANISOTROPY_EXT.

 It is acceptable for implementation to round 'N' up to the nearest
 supported sampling rate.  For example an implementation may only
 support power-of-two sampling rates.

 It is also acceptable for an implementation to approximate the ideal
 functions Px and Py with functions Fx and Fy subject to the following
 conditions:

   1.  Fx is continuous and monotonically increasing in |du/dx| and |dv/dx|.
       Fy is continuous and monotonically increasing in |du/dy| and |dv/dy|.

   2.  max(|du/dx|,|dv/dx|} <= Fx <= |du/dx| + |dv/dx|.
       max(|du/dy|,|dv/dy|} <= Fy <= |du/dy| + |dv/dy|.

 Instead of a single sample, Tau, at (u,v,Lamda), 'N' locations in the mipmap
 at LOD Lamda, are sampled within the texture footprint of the pixel.

 Instead of a single sample, Tau, at (u,v,lambda), 'N' locations in
 the mipmap at LOD Lamda are sampled within the texture footprint of
 the pixel.  This sum TauAniso is defined using the single sample Tau.
 When the texture's value of TEXTURE_MAX_ANISOTROPHY_EXT is greater
 than 1.0, use TauAniso instead of Tau to determine the fragment's
 texture value.

                i=N
                ---
 TauAniso = 1/N \ Tau(u(x - 1/2 + i/(N+1), y), v(x - 1/2 + i/(N+1), y)),  Px > Py
                /
                ---
                i=1

                i=N
                ---
 TauAniso = 1/N \ Tau(u(x, y - 1/2 + i/(N+1)), v(x, y - 1/2 + i/(N+1))),  Py >= Px
                /
                ---
                i=1

 It is acceptable to approximate the u and v functions with equally spaced
 samples in texture space at LOD Lamda:

                i=N
                ---
 TauAniso = 1/N \ Tau(u(x,y)+dudx(i/(N+1)-1/2), v(x,y)+dvdx(i/(N+1)-1/2)), Px > Py
                /
                ---
                i=1

                i=N
                ---
 TauAniso = 1/N \ Tau(u(x,y)+dudy(i/(N+1)-1/2), v(x,y)+dvdy(i/(N+1)-1/2)), Py >= Px
                /
                ---
                i=1 

```


---

