NV_shader_texture_footprint

Name

NV_shader_texture_footprint

Name Strings

GL_NV_shader_texture_footprint

Contact

Chris Lentini, NVIDIA (clentini 'at' nvidia.com)
Pat Brown, NVIDIA (pbrown 'at' nvidia.com)

Contributors

Jeff Bolz, NVIDIA
Daniel Koch, NVIDIA

Status

Shipping

Version

Last Modified Date:         February 8, 2018
NVIDIA Revision:            2

Number

OpenGL Extension #530
OpenGL ES Extension #313

Dependencies

This extension is written against the OpenGL 4.6 Specification
(Compatibility Profile), dated July 30, 2017.

OpenGL 4.5 or OpenGL ES 3.2 is required.

This extension requires support for the OpenGL Shading Language (GLSL)
extension "NV_shader_texture_footprint", which can be found at the Khronos
Group Github site here:

    https://github.com/KhronosGroup/GLSL

Overview

This extension adds OpenGL API support for the OpenGL Shading Language
(GLSL) extension "NV_shader_texture_footprint".  That extension adds a new
set of texture query functions ("textureFootprint*NV") to GLSL.  These
built-in functions prepare to perform a filtered texture lookup based on
coordinates and other parameters passed in by the calling code.  However,
instead of returning data from the provided texture image, these query
functions instead return data identifying the _texture footprint_ for an
equivalent texture access.  The texture footprint identifies a set of
texels that may be accessed in order to return a filtered result for the
texture access.

The footprint itself is a structure that includes integer values that
identify a small neighborhood of texels in the texture being accessed and
a bitfield that indicates which texels in that neighborhood would be used.
Each bit in the returned bitfield identifies whether any texel in a small
aligned block of texels would be fetched by the texture lookup.  The size
of each block is specified by an access _granularity_ provided by the
shader.  The minimum granularity supported by this extension is 2x2 (for
2D textures) and 2x2x2 (for 3D textures); the maximum granularity is
256x256 (for 2D textures) or 64x32x32 (for 3D textures).  Each footprint
query returns the footprint from a single texture level.  When using
minification filters that combine accesses from multiple mipmap levels,
shaders must perform separate queries for the two levels accessed ("fine"
and "coarse").  The footprint query also returns a flag indicating if the
texture lookup would access texels from only one mipmap level or from two
neighboring levels.

This extension should be useful for multi-pass rendering operations that
do an initial expensive rendering pass to produce a first image that is
then used as a texture for a second pass.  If the second pass ends up
accessing only portions of the first image (e.g., due to visibility), the
work spent rendering the non-accessed portion of the first image was
wasted.  With this feature, an application can limit this waste using an
initial pass over the geometry in the second image that performs a
footprint query for each visible pixel to determine the set of pixels that
it needs from the first image.  This pass would accumulate an aggregate
footprint of all visible pixels into a separate "footprint texture" using
shader atomics.  Then, when rendering the first image, the application can
kill all shading work for pixels not in this aggregate footprint.

The implementation of this extension has a number of limitations.  The
texture footprint query functions are only supported for two- and
three-dimensional textures (TEXTURE_2D, TEXTURE_3D).  Texture footprint
evaluation only supports the CLAMP_TO_EDGE wrap mode; results are
undefined for all other wrap modes.  The implementation supports only a
limited set of granularity values and does not support separate coverage
information for each texel in the original texture.

New Procedures and Functions

None

New Tokens

None

Additions to Chapter 8 of the OpenGL 4.6 (Compatibility Profile) Specification (Textures and Samplers)

(add a new section immediately after section 8.15, Texture Magnification)

Section 8.X, Texture Footprint Queries

The OpenGL Shading Language provides a collection of built-in functions,
all beginning with "textureFootprint", that allow shaders to query a
_texture footprint_.  The texture footprint is a set of texels belonging
to a single texture level that would be accessed when performing a
filtered texture lookup.  The shader code calling the footprint query
functions passes in a _granularity_ value, which is used to subdivide a
texture level into an array of fixed-size _texel groups_ whose size is
given by the granularity.  The texture footprint query functions return
the footprint using a built-in GLSL data structure that identifies the set
of texel groups containing one or more texels that would be accessed in an
equivalent texture lookup.  Texture footprint queries are only supported
for two- and three-dimensional textures (targets TEXTURE_2D and
TEXTURE_3D).  Additionally, footprint queries require the use of the
CLAMP_TO_EDGE sampler wrap mode in all relevant dimensions; the results of
the footprint query are undefined if any other wrap mode is used.

Each texture footprint query built-in function accepts a set of texture
coordinates and any additional parameters (e.g., explicit level of detail,
level of detail bias, or derivatives) needed to specify a normal texture
lookup operation whose footprint should be evaluated.  The footprint query
functions also accept a <granularity> parameter and a <coarse> flag used
to select the level of detail whose footprint is returned.  The
granularity parameter identifies the size of the texel groups used for the
footprint query as described in Table X.1.  The <coarse> flag is used to
select between the two levels of detail used when minifying using a filter
(NEAREST_MIPMAP_LINEAR, LINEAR_MIPMAP_LINEAR) that averages texels from
multiple levels of detail.  When such minification is performed, a value
of "false" requests the footprint in the higher-resolution (fine) level of
detail, while "true" requests the footprint in the lower-resolution
(coarse) level of detail.  When a texture access uses only a single level
of detail, its footprint will be returned for queries with <coarse> set to
false, while queries with <coarse> set to true will return an empty
footprint.  Since many texture accesses may use only a single level, the
footprint query functions return a boolean value, which will be true if
and only if all accessed texels are in a single level of detail.

  Granularity Value |  TEXTURE_2D   |  TEXTURE_3D
  ------------------+---------------+----------------
          0         |  unsupported  |  unsupported
          1         |      2x2      |     2x2x2
          2         |      4x2      |  unsupported
          3         |      4x4      |     4x4x2
          4         |      8x4      |  unsupported
          5         |      8x8      |  unsupported
          6         |     16x8      |  unsupported
          7         |     16x16     |  unsupported
          8         |  unsupported  |  unsupported
          9         |  unsupported  |  unsupported
          10        |  unsupported  |    16x16x16
          11        |     64x64     |    32x16x16
          12        |    128x64     |    32x32x16
          13        |    128x128    |    32x32x32
          14        |    256x128    |    64x32x32
          15        |    256x256    |  unsupported

  Table X.1:  Supported granularities for texture footprint queries, for
  two-dimensional (TEXTURE_2D) and three-dimensional (TEXTURE_3D)
  accesses.  Granularity values not listed in the table or listed as
  "unsupported" are not supported by this extension and result in
  undefined behavior if used.

  In addition to the boolean result, texture footprint queries return
  footprint data in a structure of the type gl_TextureFootprint2DNV (for
  two-dimensional textures) or gl_TextureFootprint3DNV (for
  three-dimensional textures).  In either structure, the member <lod>
  specifies the level-of-detail number used for the footprint.  The
  members <anchor> and <offset> identify a small neighborhood of texel
  groups in the texture used by the query.  The member <mask> specifies 64
  bits of data indicating which texel groups in the neighborhood are part
  of the footprint.  The member <granularity> returns information on the
  size of the texel groups in the footprint, which is sometimes larger
  than the requested granularity, as described below.

  For two-dimensional footprint queries, the neighborhood returned by the
  query is an 8x8 array of texel groups, where each texel group in
  neighborhood is identified by a coordinate (x,y), where <x> and <y> are
  integer values in the range [0,7].  Each texel group corresponds to a
  set of texels whose (u,v) coordinates satisfy the inequalities:

    u1 <= u <= u2
    v1 <= v <= v2

  computed using the following logic:

    // The footprint logic returns a mask whose bits are aligned to 8x8
    // sets of texel groups.  This allows shaders to use atomics to
    // efficiently accumulate footprint results across many invocations,
    // storing an 8x8 array of bits for each group into one RG32UI texel.
    // The texel group number in the neighborhood is treated as an offset
    // relative to the anchor point.
    uvec2 texel_group = 8 * result.anchor + uvec2(x,y);

    // If the neighborhood crosses the boundaries of an 8x8 set, the bits
    // of the mask are effectively split across multiple sets (up to
    // four for 2D).  The "offset" parameter returned by the query
    // identifies which x/y group values in the neighborhood are
    // assigned to which set.  An all-zero offset indicates that the
    // footprint is fully contained in a single 8x8 set at the anchor.
    // "Low" x/y values identify texel groups at the beginning of the 8x8
    // set identified by the anchor, while "high" values correspond to
    // texel groups at the end of the previous set.  The offset
    // indicates the number of texel groups assigned to the previous set.
    if (x + result.offset.x >= 8) {
        texel_group.x -= 8;
    }
    if (y + result.offset.y >= 8) {
        texel_group.y -= 8;
    }

    // Once we have a group number, u/v texel number ranges are generated by
    // multiplying by the texel group size.
    uint u1 = texel_group.x * granularity_x;
    uint u2 = u1 + granularity_x - 1;
    uint v1 = texel_group.y * granularity_y;
    uint v2 = v1 + granularity_y - 1;

  In the equations above, <granularity_x> and <granularity_y> refer to the
  texel group size as in Table X.1.  result.anchor and result.offset
  specify the <anchor> and <offset> members of the returned structure, and
  <x> and <y> specify the texel group number in the neighborhood.

  Each bit in the <mask> member of the returned structure corresponds to
  one of the texel groups in the 8x8 neighborhood.  That bit will be set
  if and only if any of the texels in the texel group is covered by the
  footprint.  The texel group (x,y) is considered to be covered if and
  only if the following logic computes true for <covered>:

    uint64_t mask = result.mask.x | (result.mask.y << 32);
    uint32_t bit = y * 8 + x;
    bool covered = (0 != ((mask >> bit) & 1));

  For three-dimensional footprint queries, the logic is very similar,
  except that the neighborhood returned by the query is a 4x4x4 array of
  texel groups.  Each texel group in neighborhood is identified by a
  coordinate (x,y,z), where <x>, <y>, and <z> are integer values in the
  range [0,3].  Each texel group corresponds to a set of texels whose
  (u,v,w) coordinates satisfy the inequalities:

    u1 <= u <= u2
    v1 <= v <= v2
    w1 <= w <= w2

  computed using the following logic:

    uvec3 texel_group = 4 * result.anchor + uvec3(x,y,z);
    if (x + result.offset.x >= 4) {
        texel_group.x -= 4;
    }
    if (y + result.offset.y >= 4) {
        texel_group.y -= 4;
    }
    if (z + result.offset.z >= 4) {
        texel_group.z -= 4;
    }
    uint u1 = texel_group.x * granularity_x;
    uint u2 = u1 + granularity_x - 1;
    uint v1 = texel_group.y * granularity_y;
    uint v2 = v1 + granularity_y - 1;
    uint w1 = texel_group.z * granularity_z;
    uint w2 = w1 + granularity_z - 1;

  As in the two-dimensional logic, <granularity_x>, <granularity_y>, and
  <granularity_z> refer to the texel group size as in Table X.1.
  result.anchor and result.offset specify the <anchor> and <offset>
  members of the returned structure, and <x>, <y>, and <z> specify the
  texel group number in the neighborhood.

  Each bit in the <mask> member of the returned structure corresponds to
  one of the texel groups in the 4x4x4 neighborhood.  That bit will be set
  if and only if any of the texels in the texel group is covered by the
  footprint.  The texel group (x,y,z) is considered to be covered if and
  only if the following logic computes true for <covered>:

    uint64_t mask = result.mask.x | (result.mask.y << 32);
    uint32_t bit = z * 16 + y * 4 + x;
    bool covered = (0 != ((mask >> bit) & 1));

  In most cases, the texel group sizes used by the footprint query will
  match the value passed to the query, as interpreted according to Table
  X.1.  However, in some cases, the footprint may be too large to be
  expressed as a collection of 8x8 or 4x4x4 set of texel groups using the
  requested granularity.  In this case, the implementation uses a texel
  group size that is larger than the requested granularity.  If a larger
  texel group size is used, the implementation will return the texel group
  size used in the <granularity> member of the footprint structure, which
  should also be interpreted according to Table X.1.  If the requested
  texel group size is used, the implementation will return zero in
  <granularity>.  The texel group size will only be increased by the
  implementation if anisotropic filtering is used.  If the texture and
  sampler objects used by the footprint query do not enable anisotropic
  texture filtering, the footprint query will always use the original
  requested granularity and return zero in the <granularity> member.

Errors

None

New State

None

New Implementation Dependent State

None

Issues

None, but please refer to issues in the GLSL extension specification.

Revision History

Revision 2 (pknowles)
- Add ES interactions.

Revision 1 (clentini, pbrown)
- Internal revisions.