15.8. Image Sample Operations

15.8.1. Wrapping Operation

Cube images ignore the wrap modes specified in the sampler. Instead, if VK_FILTER_NEAREST is used within a miplevel then VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE is used, and if VK_FILTER_LINEAR is used within a miplevel then sampling at the edges is performed as described earlier in the Cube map edge handling section.

The first integer texel coordinate i is transformed based on the addressModeU parameter of the sampler.

\begin{align*} i &= \begin{cases} i \operatorname{mod} size & \textrm{for repeat} \\ (size-1) - \operatorname{mirror}((i \operatorname{mod} (2 \times size)) - size) & \textrm{for mirrored repeat} \\ \operatorname{clamp}(i,0,size-1) & \textrm{for clamp to edge} \\ \operatorname{clamp}(i,-1,size) & \textrm{for clamp to border} \\ \operatorname{clamp}(\operatorname{mirror}(i),0,size-1) & \textrm{for mirror clamp to edge} \end{cases} \end{align*}


\begin{align*} &\operatorname{mirror}(n) = \begin{cases} n & \textrm{for }n \geq 0 \\ -(1+n) &\textrm{otherwise} \\ \end{cases} \end{align*}

$j$ (for 2D and Cube image) and $k$ (for 3D image) are similarly transformed based on the addressModeV and addressModeW parameters of the sampler, respectively.

15.8.2. Texel Gathering

SPIR-V instructions with Gather in the name return a vector derived from a 2x2 rectangular region of texels in the base level of the image view. The rules for the LINEAR minification filter are applied to identify the four selected texels. Each texel is then converted to an RGBA value according to conversion to RGBA and then swizzled. A four-component vector is then assembled by taking the component indicated by the Component value in the instruction from the swizzled color value of the four texels:

\begin{align*} \tau[R] &= \tau_{i0j1}[level_{base}][comp] \\ \tau[G] &= \tau_{i1j1}[level_{base}][comp] \\ \tau[B] &= \tau_{i1j0}[level_{base}][comp] \\ \tau[A] &= \tau_{i0j0}[level_{base}][comp] \end{align*}


\begin{align*} \tau[level_{base}][comp] &= \begin{cases} \tau[level_{base}][R], &\textrm{for } comp = 0 \\ \tau[level_{base}][G], &\textrm{for } comp = 1 \\ \tau[level_{base}][B], &\textrm{for } comp = 2 \\ \tau[level_{base}][A], &\textrm{for } comp = 3 \end{cases}\\ comp &\textrm{ from SPIR-V operand Component} \end{align*}

15.8.3. Texel Filtering

If $\lambda$ is less than or equal to zero, the texture is said to be magnified, and the filter mode within a mip level is selected by the magFilter in the sampler. If $\lambda$ is greater than zero, the texture is said to be minified, and the filter mode within a mip level is selected by the minFilter in the sampler.

Within a miplevel, NEAREST filtering selects a single value using the $(i,j,k)$ texel coordinates, with all texels taken from layer l.

\begin{align*} \tau[level] &= \begin{cases} \tau_{ijk}[level], &\textrm{for 3D image} \\ \tau_{ij}[level], &\textrm{for 2D or Cube image} \\ \tau_{i}[level], &\textrm{for 1D image} \end{cases} \end{align*}

Within a miplevel, LINEAR filtering computes a weighted average of 8 (for 3D), 4 (for 2D or Cube), or 2 (for 1D) texel values, using the weights computed earlier:

\begin{align*} \tau_{3D}[level] & = (1-\alpha)(1-\beta)(1-\gamma)\tau_{i0j0k0}[level] \\ & \, + (\alpha)(1-\beta)(1-\gamma)\tau_{i1j0k0}[level] \\ & \, + (1-\alpha)(\beta)(1-\gamma)\tau_{i0j1k0}[level] \\ & \, + (\alpha)(\beta)(1-\gamma)\tau_{i1j1k0}[level] \\ & \, + (1-\alpha)(1-\beta)(\gamma)\tau_{i0j0k1}[level] \\ & \, + (\alpha)(1-\beta)(\gamma)\tau_{i1j0k1}[level] \\ & \, + (1-\alpha)(\beta)(\gamma)\tau_{i0j1k1}[level] \\ & \, + (\alpha)(\beta)(\gamma)\tau_{i1j1k1}[level] \end{align*}
\begin{align*} \tau_{2D}[level] & = (1-\alpha)(1-\beta)\tau_{i0j0}[level] \\ & \, + (\alpha)(1-\beta)\tau_{i1j0}[level] \\ & \, + (1-\alpha)(\beta)\tau_{i0j1}[level] \\ & \, + (\alpha)(\beta)\tau_{i1j1}[level] \end{align*}
\begin{align*} \tau_{1D}[level] & = (1-\alpha)\tau_{i0}[level] \\ & \, + (\alpha)\tau_{i1}[level] \end{align*}
\begin{align*} \tau[level] &= \begin{cases} \tau_{3D}[level], &\textrm{for 3D image} \\ \tau_{2D}[level], &\textrm{for 2D or Cube image} \\ \tau_{1D}[level], &\textrm{for 1D image} \end{cases} \end{align*}

Finally, mipmap filtering either selects a value from one miplevel or computes a weighted average between neighboring miplevels:

\begin{align*} \tau &= \begin{cases} \tau[d], &\textrm{for mipmode BASE or NEAREST} \\ (1-\delta)\tau[d_{hi}]+\delta\tau[d_{lo}], &\textrm{for mipmode LINEAR} \end{cases} \end{align*}

15.8.4. Texel Anisotropic Filtering

Anisotropic filtering is enabled by the anisotropyEnable in the sampler. When enabled, the image filtering scheme accounts for a degree of anisotropy.

The particular scheme for anisotropic texture filtering is implementation dependent. Implementations should consider the magFilter, minFilter and mipmapMode of the sampler to control the specifics of the anisotropic filtering scheme used. In addition, implementations should consider minLod and maxLod of the sampler.

The following describes one particular approach to implementing anisotropic filtering for the 2D Image case, implementations may choose other methods:

Given a magFilter, minFilter of LINEAR and a mipmapMode of NEAREST,

Instead of a single isotropic sample, N isotropic samples are be sampled within the image footprint of the image level d to approximate an anisotropic filter. The sum $\tau_{2Daniso}$ is defined using the single isotropic $\tau_{2D}$ (u,v) at level d.

\begin{align*} \tau_{2Daniso} & = \frac{1}{N}\sum_{i=1}^{N} {\tau_{2D}\left ( u \left ( x - \frac{1}{2} + \frac{i}{N+1} , y \right ), \left ( v \left (x-\frac{1}{2}+\frac{i}{N+1} \right ), y \right ) \right )}, &\textrm{when } \rho_{x} > \rho_{y} \\ \tau_{2Daniso} &= \frac{1}{N}\sum_{i=1}^{N} {\tau_{2D}\left ( u \left ( x, y - \frac{1}{2} + \frac{i}{N+1} \right ), \left ( v \left (x,y-\frac{1}{2}+\frac{i}{N+1} \right ) \right ) \right )}, &\textrm{when } \rho_{y} \geq \rho_{x} \end{align*}

(Bill) EXT_texture_filter_anisotropic has not been updated since 2000, except for ES extension number (2007) and a minor speeling (sic) correction (2014), neither of which are functional changes. It is showing its age.

In particular, there’s an open issue about 3D textures.

There are no interactions with ARB_texture_cube_map (approved 1999, promoted to core OpenGL 1.3 in 2001), let alone interactions with ARB_seamless_cube_map (approved and promoted to core OpenGL 3.2 in 2009).

There are no interactions with texture offsets or texture gather.