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 parameter and a 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 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 set to false, while queries with 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 specifies the level-of-detail number used for the footprint. The members and identify a small neighborhood of texel groups in the texture used by the query. The member specifies 64 bits of data indicating which texel groups in the neighborhood are part of the footprint. The member 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 and 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, and refer to the texel group size as in Table X.1. result.anchor and result.offset specify the and members of the returned structure, and and specify the texel group number in the neighborhood. Each bit in the 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 : 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 , , and 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, , , and refer to the texel group size as in Table X.1. result.anchor and result.offset specify the and members of the returned structure, and , , and specify the texel group number in the neighborhood. Each bit in the 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 : 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 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 . 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 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.