| // Copyright 2015-2023 The Khronos Group Inc. |
| // |
| // SPDX-License-Identifier: CC-BY-4.0 |
| |
| [[textures]] |
| = Image Operations |
| |
| |
| == Image Operations Overview |
| |
| Vulkan Image Operations are operations performed by those SPIR-V Image |
| Instructions which take an code:OpTypeImage (representing a |
| sname:VkImageView) or code:OpTypeSampledImage (representing a |
| (sname:VkImageView, sname:VkSampler) pair). |
| Read, write, and atomic operations also take texel coordinates as operands, |
| and return a value based on a neighborhood of texture elements (_texels_) |
| within the image. |
| Query operations return properties of the bound image or of the lookup |
| itself. |
| The "`Depth`" operand of code:OpTypeImage is ignored. |
| |
| [NOTE] |
| .Note |
| ==== |
| Texel is a term which is a combination of the words texture and element. |
| Early interactive computer graphics supported texture operations on |
| textures, a small subset of the image operations on images described here. |
| The discrete samples remain essentially equivalent, however, so we retain |
| the historical term texel to refer to them. |
| ==== |
| |
| Image Operations include the functionality of the following SPIR-V Image |
| Instructions: |
| |
| * code:OpImageSample* and code:OpImageSparseSample* read one or more |
| neighboring texels of the image, and <<textures-texel-filtering,filter>> |
| the texel values based on the state of the sampler. |
| ** Instructions with code:ImplicitLod in the name |
| <<textures-level-of-detail-operation,determine>> the LOD used in the |
| sampling operation based on the coordinates used in neighboring |
| fragments. |
| ** Instructions with code:ExplicitLod in the name |
| <<textures-level-of-detail-operation,determine>> the LOD used in the |
| sampling operation based on additional coordinates. |
| ** Instructions with code:Proj in the name apply homogeneous |
| <<textures-projection,projection>> to the coordinates. |
| * code:OpImageFetch and code:OpImageSparseFetch return a single texel of |
| the image. |
| No sampler is used. |
| * code:OpImage*Gather and code:OpImageSparse*Gather read neighboring |
| texels and <<textures-gather,return a single component>> of each. |
| * code:OpImageRead (and code:OpImageSparseRead) and code:OpImageWrite read |
| and write, respectively, a texel in the image. |
| No sampler is used. |
| ifdef::VK_NV_shader_image_footprint[] |
| * code:OpImageSampleFootprintNV identifies and returns information about |
| the set of texels in the image that would be accessed by an equivalent |
| code:OpImageSample* instruction. |
| endif::VK_NV_shader_image_footprint[] |
| * code:OpImage*Dref* instructions apply |
| <<textures-depth-compare-operation,depth comparison>> on the texel |
| values. |
| * code:OpImageSparse* instructions additionally return a |
| <<textures-sparse-residency,sparse residency>> code. |
| * code:OpImageQuerySize, code:OpImageQuerySizeLod, |
| code:OpImageQueryLevels, and code:OpImageQuerySamples return properties |
| of the image descriptor that would be accessed. |
| The image itself is not accessed. |
| * code:OpImageQueryLod returns the LOD parameters that would be used in a |
| sample operation. |
| The actual operation is not performed. |
| ifdef::VK_QCOM_image_processing[] |
| * code:OpImageWeightedSampleQCOM reads a 2D neighborhood of texels and |
| computes a weighted average using weight values from a separate weight |
| texture. |
| * code:opImageBlockMatchSADQCOM and code:opTextureBlockMatchSSD compare 2D |
| neighborhoods of texels from two textures. |
| * code:OpImageBoxFilterQCOM reads a 2D neighborhood of texels and computes |
| a weighted average of the texels. |
| endif::VK_QCOM_image_processing[] |
| ifdef::VK_QCOM_image_processing2[] |
| * code:opImageBlockMatchWindowSADQCOM and |
| code:opImageBlockMatchWindowSSDQCOM compare 2D neighborhoods of texels |
| from two textures with the comparison repeated across a window region in |
| the target texture. |
| * code:opImageBlockMatchGatherSADQCOM and |
| code:opImageBlockMatchWindowSSDQCOM compares four 2D neighborhoods of |
| texels from a target texture with a single 2D neighborhood in the |
| reference texture. |
| The R component of each comparison is gathered and returned in the |
| output. |
| endif::VK_QCOM_image_processing2[] |
| |
| |
| [[textures-texel-coordinate-systems]] |
| === Texel Coordinate Systems |
| |
| Images are addressed by _texel coordinates_. |
| There are three _texel coordinate systems_: |
| |
| * normalized texel coordinates [eq]#[0.0, 1.0]# |
| * unnormalized texel coordinates [eq]#[0.0, width / height / depth)# |
| * integer texel coordinates [eq]#[0, width / height / depth)# |
| |
| SPIR-V code:OpImageFetch, code:OpImageSparseFetch, code:OpImageRead, |
| code:OpImageSparseRead, |
| ifdef::VK_QCOM_image_processing[] |
| code:opImageBlockMatchSADQCOM, code:opImageBlockMatchSSDQCOM, |
| endif::VK_QCOM_image_processing[] |
| ifdef::VK_QCOM_image_processing2[] |
| code:opImageBlockMatchWindowSADQCOM, code:opImageBlockMatchWindowSSDQCOM, |
| endif::VK_QCOM_image_processing2[] |
| and code:OpImageWrite instructions use integer texel coordinates. |
| |
| Other image instructions can: use either normalized or unnormalized texel |
| coordinates (selected by the pname:unnormalizedCoordinates state of the |
| sampler used in the instruction), but there are |
| <<samplers-unnormalizedCoordinates,limitations>> on what operations, image |
| state, and sampler state is supported. |
| Normalized coordinates are logically |
| <<textures-normalized-to-unnormalized,converted>> to unnormalized as part of |
| image operations, and <<textures-normalized-operations,certain steps>> are |
| only performed on normalized coordinates. |
| The array layer coordinate is always treated as unnormalized even when other |
| coordinates are normalized. |
| |
| Normalized texel coordinates are referred to as [eq]#(s,t,r,q,a)#, with the |
| coordinates having the following meanings: |
| |
| * [eq]#s#: Coordinate in the first dimension of an image. |
| * [eq]#t#: Coordinate in the second dimension of an image. |
| * [eq]#r#: Coordinate in the third dimension of an image. |
| ** [eq]#(s,t,r)# are interpreted as a direction vector for Cube images. |
| * [eq]#q#: Fourth coordinate, for homogeneous (projective) coordinates. |
| * [eq]#a#: Coordinate for array layer. |
| |
| The coordinates are extracted from the SPIR-V operand based on the |
| dimensionality of the image variable and type of instruction. |
| For code:Proj instructions, the components are in order [eq]#(s, [t,] [r,] |
| q)#, with [eq]#t# and [eq]#r# being conditionally present based on the |
| code:Dim of the image. |
| For non-code:Proj instructions, the coordinates are [eq]#(s [,t] [,r] |
| [,a])#, with [eq]#t# and [eq]#r# being conditionally present based on the |
| code:Dim of the image and [eq]#a# being conditionally present based on the |
| code:Arrayed property of the image. |
| Projective image instructions are not supported on code:Arrayed images. |
| |
| Unnormalized texel coordinates are referred to as [eq]#(u,v,w,a)#, with the |
| coordinates having the following meanings: |
| |
| * [eq]#u#: Coordinate in the first dimension of an image. |
| * [eq]#v#: Coordinate in the second dimension of an image. |
| * [eq]#w#: Coordinate in the third dimension of an image. |
| * [eq]#a#: Coordinate for array layer. |
| |
| Only the [eq]#u# and [eq]#v# coordinates are directly extracted from the |
| SPIR-V operand, because only 1D and 2D (non-code:Arrayed) dimensionalities |
| support unnormalized coordinates. |
| The components are in order [eq]#(u [,v])#, with [eq]#v# being conditionally |
| present when the dimensionality is 2D. |
| When normalized coordinates are converted to unnormalized coordinates, all |
| four coordinates are used. |
| |
| Integer texel coordinates are referred to as [eq]#(i,j,k,l,n)#, with the |
| coordinates having the following meanings: |
| |
| * [eq]#i#: Coordinate in the first dimension of an image. |
| * [eq]#j#: Coordinate in the second dimension of an image. |
| * [eq]#k#: Coordinate in the third dimension of an image. |
| * [eq]#l#: Coordinate for array layer. |
| * [eq]#n#: Index of the sample within the texel. |
| |
| They are extracted from the SPIR-V operand in order [eq]#(i [,j] [,k] [,l] |
| [,n])#, with [eq]#j# and [eq]#k# conditionally present based on the code:Dim |
| of the image, and [eq]#l# conditionally present based on the code:Arrayed |
| property of the image. |
| [eq]#n# is conditionally present and is taken from the code:Sample image |
| operand. |
| |
| ifdef::VK_EXT_image_sliced_view_of_3d[] |
| If an accessed image was created from a view using |
| slink:VkImageViewSlicedCreateInfoEXT and accessed through a |
| ename:VK_DESCRIPTOR_TYPE_STORAGE_IMAGE descriptor, then the value of [eq]#k# |
| is incremented by slink:VkImageViewSlicedCreateInfoEXT::pname:sliceOffset, |
| giving [eq]#k <- sliceOffset {plus} k#. |
| The image's accessible range in the third dimension is [eq]#k < sliceOffset |
| + sliceCount#. |
| If slink:VkImageViewSlicedCreateInfoEXT::pname:sliceCount is |
| ename:VK_REMAINING_3D_SLICES_EXT, the range is inherited from the image's |
| depth extent as specified by <<resources-image-mip-level-sizing, Image Mip |
| Level Sizing>>. |
| endif::VK_EXT_image_sliced_view_of_3d[] |
| |
| For all coordinate types, unused coordinates are assigned a value of zero. |
| |
| [[textures-texel-coordinate-systems-diagrams]] |
| image::{images}/vulkantexture0-ll.svg[align="center",title="Texel Coordinate Systems, Linear Filtering",opts="{imageopts}"] |
| The Texel Coordinate Systems - For the example shown of an 8{times}4 texel |
| two dimensional image. |
| |
| * Normalized texel coordinates: |
| ** The [eq]#s# coordinate goes from 0.0 to 1.0. |
| ** The [eq]#t# coordinate goes from 0.0 to 1.0. |
| * Unnormalized texel coordinates: |
| ** The [eq]#u# coordinate within the range 0.0 to 8.0 is within the image, |
| otherwise it is outside the image. |
| ** The [eq]#v# coordinate within the range 0.0 to 4.0 is within the image, |
| otherwise it is outside the image. |
| * Integer texel coordinates: |
| ** The [eq]#i# coordinate within the range 0 to 7 addresses texels within |
| the image, otherwise it is outside the image. |
| ** The [eq]#j# coordinate within the range 0 to 3 addresses texels within |
| the image, otherwise it is outside the image. |
| * Also shown for linear filtering: |
| ** Given the unnormalized coordinates [eq]#(u,v)#, the four texels |
| selected are [eq]#i~0~j~0~#, [eq]#i~1~j~0~#, [eq]#i~0~j~1~#, and |
| [eq]#i~1~j~1~#. |
| ** The fractions [eq]#{alpha}# and [eq]#{beta}#. |
| ** Given the offset [eq]#{DeltaUpper}~i~# and [eq]#{DeltaUpper}~j~#, the |
| four texels selected by the offset are [eq]#i~0~j'~0~#, |
| [eq]#i~1~j'~0~#, [eq]#i~0~j'~1~#, and [eq]#i~1~j'~1~#. |
| |
| ifdef::VK_VERSION_1_1,VK_KHR_sampler_ycbcr_conversion[] |
| [NOTE] |
| .Note |
| ==== |
| For formats with reduced-resolution components, [eq]#{DeltaUpper}~i~# and |
| [eq]#{DeltaUpper}~j~# are relative to the resolution of the |
| highest-resolution component, and therefore may be divided by two relative |
| to the unnormalized coordinate space of the lower-resolution components. |
| ==== |
| endif::VK_VERSION_1_1,VK_KHR_sampler_ycbcr_conversion[] |
| |
| image::{images}/vulkantexture1-ll.svg[align="center",title="Texel Coordinate Systems, Nearest Filtering",opts="{imageopts}"] |
| |
| The Texel Coordinate Systems - For the example shown of an 8{times}4 texel |
| two dimensional image. |
| |
| * Texel coordinates as above. |
| Also shown for nearest filtering: |
| ** Given the unnormalized coordinates [eq]#(u,v)#, the texel selected is |
| [eq]#ij#. |
| ** Given the offset [eq]#{DeltaUpper}~i~# and [eq]#{DeltaUpper}~j~#, the |
| texel selected by the offset is [eq]#ij'#. |
| |
| ifdef::VK_NV_corner_sampled_image[] |
| For corner-sampled images, the texel samples are located at the grid |
| intersections instead of the texel centers. |
| |
| image::{images}/vulkantexture0-corner-alternative-a-ll.svg[align="center",title="Texel Coordinate Systems, Corner Sampling",opts="{imageopts}"] |
| |
| endif::VK_NV_corner_sampled_image[] |
| |
| |
| == Conversion Formulas |
| |
| ifdef::editing-notes[] |
| [NOTE] |
| .editing-note |
| ==== |
| (Bill) These Conversion Formulas will likely move to Section 2.7 Fixed-Point |
| Data Conversions (RGB to sRGB and sRGB to RGB) and section 2.6 Numeric |
| Representation and Computation (RGB to Shared Exponent and Shared Exponent |
| to RGB) |
| ==== |
| endif::editing-notes[] |
| |
| |
| [[textures-RGB-sexp]] |
| === RGB to Shared Exponent Conversion |
| |
| An RGB color [eq]#(red, green, blue)# is transformed to a shared exponent |
| color [eq]#(red~shared~, green~shared~, blue~shared~, exp~shared~)# as |
| follows: |
| |
| First, the components [eq]#(red, green, blue)# are clamped to |
| [eq]#(red~clamped~, green~clamped~, blue~clamped~)# as: |
| |
| {empty}:: [eq]#red~clamped~ = max(0, min(sharedexp~max~, red))# |
| {empty}:: [eq]#green~clamped~ = max(0, min(sharedexp~max~, green))# |
| {empty}:: [eq]#blue~clamped~ = max(0, min(sharedexp~max~, blue))# |
| |
| where: |
| |
| [latexmath] |
| +++++++++++++++++++ |
| \begin{aligned} |
| N & = 9 & \text{number of mantissa bits per component} \\ |
| B & = 15 & \text{exponent bias} \\ |
| E_{max} & = 31 & \text{maximum possible biased exponent value} \\ |
| sharedexp_{max} & = \frac{(2^N-1)}{2^N} \times 2^{(E_{max}-B)} |
| \end{aligned} |
| +++++++++++++++++++ |
| |
| [NOTE] |
| .Note |
| ==== |
| // The trailing + is to avoid the asciidoc parser treating the custom role |
| // as a block attribute in some cases. |
| [eq]#NaN#, if supported, is handled as in + |
| <<ieee-754,IEEE 754-2008>> `minNum()` and `maxNum()`. |
| This results in any [eq]#NaN# being mapped to zero. |
| ==== |
| |
| The largest clamped component, [eq]#max~clamped~# is determined: |
| |
| {empty}:: [eq]#max~clamped~ = max(red~clamped~, green~clamped~, |
| blue~clamped~)# |
| |
| A preliminary shared exponent [eq]#exp'# is computed: |
| [latexmath] |
| +++++++++++++++++++ |
| \begin{aligned} |
| exp' = |
| \begin{cases} |
| \left \lfloor \log_2(max_{clamped}) \right \rfloor + (B+1) |
| & \text{for}\ max_{clamped} > 2^{-(B+1)} \\ |
| 0 |
| & \text{for}\ max_{clamped} \leq 2^{-(B+1)} |
| \end{cases} |
| \end{aligned} |
| +++++++++++++++++++ |
| |
| The shared exponent [eq]#exp~shared~# is computed: |
| |
| [latexmath] |
| +++++++++++++++++++ |
| \begin{aligned} |
| max_{shared} = |
| \left \lfloor |
| { \frac{max_{clamped}}{2^{(exp'-B-N)}} + \frac{1}{2} } |
| \right \rfloor |
| \end{aligned} |
| +++++++++++++++++++ |
| |
| [latexmath] |
| +++++++++++++++++++ |
| \begin{aligned} |
| exp_{shared} = |
| \begin{cases} |
| exp' & \text{for}\ 0 \leq max_{shared} < 2^N \\ |
| exp'+1 & \text{for}\ max_{shared} = 2^N |
| \end{cases} |
| \end{aligned} |
| +++++++++++++++++++ |
| |
| Finally, three integer values in the range [eq]#0# to [eq]#2^N^# are |
| computed: |
| |
| [latexmath] |
| +++++++++++++++++++ |
| \begin{aligned} |
| red_{shared} & = |
| \left \lfloor |
| { \frac{red_{clamped}}{2^{(exp_{shared}-B-N)}}+ \frac{1}{2} } |
| \right \rfloor \\ |
| green_{shared} & = |
| \left \lfloor |
| { \frac{green_{clamped}}{2^{(exp_{shared}-B-N)}}+ \frac{1}{2} } |
| \right \rfloor \\ |
| blue_{shared} & = |
| \left \lfloor |
| { \frac{blue_{clamped}}{2^{(exp_{shared}-B-N)}}+ \frac{1}{2} } |
| \right \rfloor |
| \end{aligned} |
| +++++++++++++++++++ |
| |
| |
| [[textures-sexp-RGB]] |
| === Shared Exponent to RGB |
| |
| A shared exponent color [eq]#(red~shared~, green~shared~, blue~shared~, |
| exp~shared~)# is transformed to an RGB color [eq]#(red, green, blue)# as |
| follows: |
| |
| {empty}:: latexmath:[red = red_{shared} \times {2^{(exp_{shared}-B-N)}}] |
| {empty}:: latexmath:[green = green_{shared} \times |
| {2^{(exp_{shared}-B-N)}}] |
| {empty}:: latexmath:[blue = blue_{shared} \times {2^{(exp_{shared}-B-N)}}] |
| |
| where: |
| |
| {empty}:: [eq]#N = 9# (number of mantissa bits per component) |
| {empty}:: [eq]#B = 15# (exponent bias) |
| |
| |
| == Texel Input Operations |
| |
| _Texel input instructions_ are SPIR-V image instructions that read from an |
| image. |
| _Texel input operations_ are a set of steps that are performed on state, |
| coordinates, and texel values while processing a texel input instruction, |
| and which are common to some or all texel input instructions. |
| They include the following steps, which are performed in the listed order: |
| |
| * <<textures-input-validation,Validation operations>> |
| ** <<textures-operation-validation,Instruction/Sampler/Image validation>> |
| ** <<textures-integer-coordinate-validation,Coordinate validation>> |
| ** <<textures-sparse-validation,Sparse validation>> |
| ifdef::VK_VERSION_1_1,VK_KHR_sampler_ycbcr_conversion[] |
| ** <<textures-layout-validation,Layout validation>> |
| endif::VK_VERSION_1_1,VK_KHR_sampler_ycbcr_conversion[] |
| * <<textures-format-conversion,Format conversion>> |
| * <<textures-texel-replacement,Texel replacement>> |
| * <<textures-depth-compare-operation,Depth comparison>> |
| * <<textures-conversion-to-rgba,Conversion to RGBA>> |
| * <<textures-component-swizzle,Component swizzle>> |
| ifdef::VK_VERSION_1_1,VK_KHR_sampler_ycbcr_conversion[] |
| * <<textures-chroma-reconstruction,Chroma reconstruction>> |
| * <<textures-sampler-YCbCr-conversion,{YCbCr} conversion>> |
| endif::VK_VERSION_1_1,VK_KHR_sampler_ycbcr_conversion[] |
| |
| For texel input instructions involving multiple texels (for sampling or |
| gathering), these steps are applied for each texel that is used in the |
| instruction. |
| Depending on the type of image instruction, other steps are conditionally |
| performed between these steps or involving multiple coordinate or texel |
| values. |
| |
| ifdef::VK_VERSION_1_1,VK_KHR_sampler_ycbcr_conversion[] |
| If <<textures-chroma-reconstruction,Chroma Reconstruction>> is implicit, |
| <<textures-texel-filtering, Texel Filtering>> instead takes place during |
| chroma reconstruction, before <<textures-sampler-YCbCr-conversion,sampler |
| {YCbCr} conversion>> occurs. |
| endif::VK_VERSION_1_1,VK_KHR_sampler_ycbcr_conversion[] |
| |
| ifdef::VK_QCOM_image_processing[] |
| The operations described in <<textures-blockmatch,block matching>> and |
| <<textures-weightimage,weight image sampling>> are performed before |
| <<textures-conversion-to-rgba,Conversion to RGBA>> and |
| <<textures-component-swizzle,Component swizzle>>. |
| endif::VK_QCOM_image_processing[] |
| |
| |
| [[textures-input-validation]] |
| === Texel Input Validation Operations |
| |
| _Texel input validation operations_ inspect instruction/image/sampler state |
| or coordinates, and in certain circumstances cause the texel value to be |
| replaced or become undefined:. |
| There are a series of validations that the texel undergoes. |
| |
| |
| [[textures-operation-validation]] |
| ==== Instruction/Sampler/Image View Validation |
| |
| There are a number of cases where a SPIR-V instruction can: mismatch with |
| the sampler, the image view, or both, and a number of further cases where |
| the sampler can: mismatch with the image view. |
| In such cases the value of the texel returned is undefined:. |
| |
| These cases include: |
| |
| * The sampler pname:borderColor is an integer type and the image view |
| pname:format is not one of the elink:VkFormat integer types or a stencil |
| component of a depth/stencil format. |
| * The sampler pname:borderColor is a float type and the image view |
| pname:format is not one of the elink:VkFormat float types or a depth |
| component of a depth/stencil format. |
| ifndef::VK_EXT_border_color_swizzle[] |
| * The sampler pname:borderColor is one of the opaque black colors |
| (ename:VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK or |
| ename:VK_BORDER_COLOR_INT_OPAQUE_BLACK) and the image view |
| elink:VkComponentSwizzle for any of the slink:VkComponentMapping |
| components is not the <<resources-image-views-identity-mappings,identity |
| swizzle>>. |
| endif::VK_EXT_border_color_swizzle[] |
| ifdef::VK_EXT_border_color_swizzle[] |
| * The sampler pname:borderColor is one of the opaque black colors |
| (ename:VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK or |
| ename:VK_BORDER_COLOR_INT_OPAQUE_BLACK) and the image view |
| elink:VkComponentSwizzle for any of the slink:VkComponentMapping |
| components is not the <<resources-image-views-identity-mappings,identity |
| swizzle>>, and |
| slink:VkPhysicalDeviceBorderColorSwizzleFeaturesEXT::pname:borderColorSwizzleFromImage |
| feature is not enabled, and |
| slink:VkSamplerBorderColorComponentMappingCreateInfoEXT is not |
| specified. |
| * slink:VkSamplerBorderColorComponentMappingCreateInfoEXT::pname:components, |
| if specified, has a component swizzle that does not match the component |
| swizzle of the image view, and either component swizzle is not a form of |
| identity swizzle. |
| * slink:VkSamplerBorderColorComponentMappingCreateInfoEXT::pname:srgb, if |
| specified, does not match the sRGB encoding of the image view. |
| endif::VK_EXT_border_color_swizzle[] |
| ifdef::VK_EXT_custom_border_color[] |
| * The sampler pname:borderColor is a custom color |
| (ename:VK_BORDER_COLOR_FLOAT_CUSTOM_EXT or |
| ename:VK_BORDER_COLOR_INT_CUSTOM_EXT) and the supplied |
| slink:VkSamplerCustomBorderColorCreateInfoEXT::pname:customBorderColor |
| is outside the bounds of the values representable in the image view's |
| pname:format. |
| ifndef::VK_EXT_border_color_swizzle[] |
| * The sampler pname:borderColor is a custom color |
| (ename:VK_BORDER_COLOR_FLOAT_CUSTOM_EXT or |
| ename:VK_BORDER_COLOR_INT_CUSTOM_EXT) and the image view |
| elink:VkComponentSwizzle for any of the slink:VkComponentMapping |
| components is not the <<resources-image-views-identity-mappings,identity |
| swizzle>>. |
| endif::VK_EXT_border_color_swizzle[] |
| ifdef::VK_EXT_border_color_swizzle[] |
| * The sampler pname:borderColor is a custom color |
| (ename:VK_BORDER_COLOR_FLOAT_CUSTOM_EXT or |
| ename:VK_BORDER_COLOR_INT_CUSTOM_EXT) and the image view |
| elink:VkComponentSwizzle for any of the slink:VkComponentMapping |
| components is not the <<resources-image-views-identity-mappings,identity |
| swizzle>>, and |
| slink:VkPhysicalDeviceBorderColorSwizzleFeaturesEXT::pname:borderColorSwizzleFromImage |
| feature is not enabled, and |
| slink:VkSamplerBorderColorComponentMappingCreateInfoEXT is not |
| specified. |
| endif::VK_EXT_border_color_swizzle[] |
| endif::VK_EXT_custom_border_color[] |
| * The elink:VkImageLayout of any subresource in the image view does not |
| match the slink:VkDescriptorImageInfo::pname:imageLayout used to write |
| the image descriptor. |
| * The SPIR-V Image Format is not <<spirvenv-image-formats,compatible>> |
| with the image view's pname:format. |
| * The sampler pname:unnormalizedCoordinates is ename:VK_TRUE and any of |
| the <<samplers-unnormalizedCoordinates,limitations of unnormalized |
| coordinates>> are violated. |
| ifdef::VK_EXT_fragment_density_map[] |
| * The sampler was created with pname:flags containing |
| ename:VK_SAMPLER_CREATE_SUBSAMPLED_BIT_EXT and the image was not created |
| with pname:flags containing ename:VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT. |
| * The sampler was not created with pname:flags containing |
| ename:VK_SAMPLER_CREATE_SUBSAMPLED_BIT_EXT and the image was created |
| with pname:flags containing ename:VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT. |
| * The sampler was created with pname:flags containing |
| ename:VK_SAMPLER_CREATE_SUBSAMPLED_BIT_EXT and is used with a function |
| that is not code:OpImageSampleImplicitLod or |
| code:OpImageSampleExplicitLod, or is used with operands code:Offset or |
| code:ConstOffsets. |
| endif::VK_EXT_fragment_density_map[] |
| * The SPIR-V instruction is one of the code:OpImage*Dref* instructions and |
| the sampler pname:compareEnable is ename:VK_FALSE |
| * The SPIR-V instruction is not one of the code:OpImage*Dref* instructions |
| and the sampler pname:compareEnable is ename:VK_TRUE |
| ifndef::VK_VERSION_1_3,VK_KHR_format_feature_flags2[] |
| * The SPIR-V instruction is one of the code:OpImage*Dref* instructions and |
| the image view pname:format is not one of the depth/stencil formats with |
| a depth component, or the image view aspect is not |
| ename:VK_IMAGE_ASPECT_DEPTH_BIT. |
| endif::VK_VERSION_1_3,VK_KHR_format_feature_flags2[] |
| ifdef::VK_VERSION_1_3,VK_KHR_format_feature_flags2[] |
| * The SPIR-V instruction is one of the code:OpImage*Dref* instructions, |
| the image view pname:format is one of the depth/stencil formats, and the |
| image view aspect is not ename:VK_IMAGE_ASPECT_DEPTH_BIT. |
| endif::VK_VERSION_1_3,VK_KHR_format_feature_flags2[] |
| * The SPIR-V instruction's image variable's properties are not compatible |
| with the image view: |
| ** Rules for pname:viewType: |
| *** ename:VK_IMAGE_VIEW_TYPE_1D must: have code:Dim = 1D, code:Arrayed = |
| 0, code:MS = 0. |
| *** ename:VK_IMAGE_VIEW_TYPE_2D must: have code:Dim = 2D, code:Arrayed = 0. |
| *** ename:VK_IMAGE_VIEW_TYPE_3D must: have code:Dim = 3D, code:Arrayed = |
| 0, code:MS = 0. |
| *** ename:VK_IMAGE_VIEW_TYPE_CUBE must: have code:Dim = Cube, code:Arrayed |
| = 0, code:MS = 0. |
| *** ename:VK_IMAGE_VIEW_TYPE_1D_ARRAY must: have code:Dim = 1D, |
| code:Arrayed = 1, code:MS = 0. |
| *** ename:VK_IMAGE_VIEW_TYPE_2D_ARRAY must: have code:Dim = 2D, |
| code:Arrayed = 1. |
| *** ename:VK_IMAGE_VIEW_TYPE_CUBE_ARRAY must: have code:Dim = Cube, |
| code:Arrayed = 1, code:MS = 0. |
| ** If the image was created with slink:VkImageCreateInfo::pname:samples |
| equal to ename:VK_SAMPLE_COUNT_1_BIT, the instruction must: have |
| code:MS = 0. |
| ** If the image was created with slink:VkImageCreateInfo::pname:samples |
| not equal to ename:VK_SAMPLE_COUNT_1_BIT, the instruction must: have |
| code:MS = 1. |
| ** If the code:Sampled code:Type of the code:OpTypeImage does not match |
| the <<spirv-type,SPIR-V Type>>. |
| ** If the <<spirvenv-image-signedness,signedness of any read or sample |
| operation>> does not match the signedness of the image's format. |
| ifdef::VK_NV_corner_sampled_image[] |
| * If the image was created with slink:VkImageCreateInfo::pname:flags |
| containing ename:VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV, the sampler |
| addressing modes must: only use a elink:VkSamplerAddressMode of |
| ename:VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE. |
| endif::VK_NV_corner_sampled_image[] |
| ifdef::VK_NV_shader_image_footprint[] |
| * The SPIR-V instruction is code:OpImageSampleFootprintNV with code:Dim = |
| 2D and pname:addressModeU or pname:addressModeV in the sampler is not |
| ename:VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE. |
| * The SPIR-V instruction is code:OpImageSampleFootprintNV with code:Dim = |
| 3D and pname:addressModeU, pname:addressModeV, or pname:addressModeW in |
| the sampler is not ename:VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE. |
| endif::VK_NV_shader_image_footprint[] |
| ifdef::VK_EXT_custom_border_color[] |
| * The sampler was created with a specified |
| slink:VkSamplerCustomBorderColorCreateInfoEXT::pname:format which does |
| not match the elink:VkFormat of the image view(s) it is sampling. |
| * The sampler is sampling an image view of |
| ename:VK_FORMAT_B4G4R4A4_UNORM_PACK16, |
| ename:VK_FORMAT_B5G6R5_UNORM_PACK16, or |
| ename:VK_FORMAT_B5G5R5A1_UNORM_PACK16 format without a specified |
| slink:VkSamplerCustomBorderColorCreateInfoEXT::pname:format. |
| endif::VK_EXT_custom_border_color[] |
| |
| ifdef::VK_VERSION_1_1,VK_KHR_sampler_ycbcr_conversion[] |
| Only code:OpImageSample* and code:OpImageSparseSample* can: be used with a |
| sampler or image view that enables <<samplers-YCbCr-conversion,sampler |
| {YCbCr} conversion>>. |
| |
| code:OpImageFetch, code:OpImageSparseFetch, code:OpImage*Gather, and |
| code:OpImageSparse*Gather must: not be used with a sampler or image view |
| that enables <<samplers-YCbCr-conversion,sampler {YCbCr} conversion>>. |
| |
| The code:ConstOffset and code:Offset operands must: not be used with a |
| sampler or image view that enables <<samplers-YCbCr-conversion,sampler |
| {YCbCr} conversion>>. |
| endif::VK_VERSION_1_1,VK_KHR_sampler_ycbcr_conversion[] |
| |
| |
| [[textures-integer-coordinate-validation]] |
| ==== Integer Texel Coordinate Validation |
| |
| Integer texel coordinates are validated against the size of the image level, |
| and the number of layers and number of samples in the image. |
| For SPIR-V instructions that use integer texel coordinates, this is |
| performed directly on the integer coordinates. |
| For instructions that use normalized or unnormalized texel coordinates, this |
| is performed on the coordinates that result after |
| <<textures-unnormalized-to-integer,conversion>> to integer texel |
| coordinates. |
| |
| If the integer texel coordinates do not satisfy all of the conditions |
| |
| {empty}:: [eq]#0 {leq} i < w~s~# |
| {empty}:: [eq]#0 {leq} j < h~s~# |
| {empty}:: [eq]#0 {leq} k < d~s~# |
| {empty}:: [eq]#0 {leq} l < layers# |
| {empty}:: [eq]#0 {leq} n < samples# |
| |
| where: |
| |
| {empty}:: [eq]#w~s~ =# width of the image level |
| {empty}:: [eq]#h~s~ =# height of the image level |
| {empty}:: [eq]#d~s~ =# depth of the image level |
| {empty}:: [eq]#layers =# number of layers in the image |
| {empty}:: [eq]#samples =# number of samples per texel in the image |
| |
| then the texel fails integer texel coordinate validation. |
| |
| There are four cases to consider: |
| |
| . Valid Texel Coordinates |
| + |
| * If the texel coordinates pass validation (that is, the coordinates lie |
| within the image), |
| + |
| then the texel value comes from the value in image memory. |
| |
| . Border Texel |
| + |
| * If the texel coordinates fail validation, and |
| * If the read is the result of an image sample instruction or image gather |
| instruction, and |
| * If the image is not a cube image, |
| ifdef::VK_EXT_non_seamless_cube_map[] |
| or if a sampler created with |
| ename:VK_SAMPLER_CREATE_NON_SEAMLESS_CUBE_MAP_BIT_EXT is used, |
| endif::VK_EXT_non_seamless_cube_map[] |
| |
| + |
| then the texel is a border texel and <<textures-texel-replacement,texel |
| replacement>> is performed. |
| |
| . Invalid Texel |
| + |
| * If the texel coordinates fail validation, and |
| * If the read is the result of an image fetch instruction, image read |
| instruction, or atomic instruction, |
| + |
| then the texel is an invalid texel and <<textures-texel-replacement,texel |
| replacement>> is performed. |
| |
| . Cube Map Edge or Corner |
| + |
| Otherwise the texel coordinates lie beyond the edges or corners of the |
| selected cube map face, and <<textures-cubemapedge, Cube map edge handling>> |
| is performed. |
| |
| |
| [[textures-cubemapedge]] |
| ==== Cube Map Edge Handling |
| |
| If the texel coordinates lie beyond the edges or corners of the selected |
| cube map face (as described in the prior section), the following steps are |
| performed. |
| Note that this does not occur when using ename:VK_FILTER_NEAREST filtering |
| within a mip level, since ename:VK_FILTER_NEAREST is treated as using |
| ename:VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE. |
| |
| * Cube Map Edge Texel |
| + |
| ** If the texel lies beyond the selected cube map face in either only |
| [eq]#i# or only [eq]#j#, then the coordinates [eq]#(i,j)# and the array |
| layer [eq]#l# are transformed to select the adjacent texel from the |
| appropriate neighboring face. |
| |
| * Cube Map Corner Texel |
| + |
| ** If the texel lies beyond the selected cube map face in both [eq]#i# and |
| [eq]#j#, then there is no unique neighboring face from which to read |
| that texel. |
| The texel should: be replaced by the average of the three values of the |
| adjacent texels in each incident face. |
| However, implementations may: replace the cube map corner texel by |
| other methods. |
| ifndef::VK_EXT_filter_cubic[] |
| The methods are subject to the constraint that if the three available texels |
| have the same value, the resulting filtered texel must: have that value. |
| endif::VK_EXT_filter_cubic[] |
| ifdef::VK_EXT_filter_cubic[] |
| The methods are subject to the constraint that for linear filtering if the |
| three available texels have the same value, the resulting filtered texel |
| must: have that value, and for cubic filtering if the twelve available |
| samples have the same value, the resulting filtered texel must: have that |
| value. |
| endif::VK_EXT_filter_cubic[] |
| |
| |
| [[textures-sparse-validation]] |
| ==== Sparse Validation |
| |
| If the texel reads from an unbound region of a sparse image, the texel is a |
| _sparse unbound texel_, and processing continues with |
| <<textures-texel-replacement,texel replacement>>. |
| |
| |
| ifdef::VK_VERSION_1_1,VK_KHR_sampler_ycbcr_conversion[] |
| [[textures-layout-validation]] |
| ==== Layout Validation |
| |
| If all planes of a _disjoint_ _multi-planar_ image are not in the same |
| <<resources-image-layouts,image layout>>, the image must: not be sampled |
| with <<samplers-YCbCr-conversion,sampler {YCbCr} conversion>> enabled. |
| |
| endif::VK_VERSION_1_1,VK_KHR_sampler_ycbcr_conversion[] |
| |
| |
| [[textures-format-conversion]] |
| === Format Conversion |
| |
| Texels undergo a format conversion from the elink:VkFormat of the image view |
| to a vector of either floating point or signed or unsigned integer |
| components, with the number of components based on the number of components |
| present in the format. |
| |
| * Color formats have one, two, three, or four components, according to the |
| format. |
| * Depth/stencil formats are one component. |
| The depth or stencil component is selected by the pname:aspectMask of |
| the image view. |
| |
| Each component is converted based on its type and size (as defined in the |
| <<formats-definition,Format Definition>> section for each elink:VkFormat), |
| using the appropriate equations in <<fundamentals-fp16,16-Bit Floating-Point |
| Numbers>>, <<fundamentals-fp11,Unsigned 11-Bit Floating-Point Numbers>>, |
| <<fundamentals-fp10,Unsigned 10-Bit Floating-Point Numbers>>, |
| <<fundamentals-fixedconv,Fixed-Point Data Conversion>>, and |
| <<textures-sexp-RGB,Shared Exponent to RGB>>. |
| Signed integer components smaller than 32 bits are sign-extended. |
| |
| If the image view format is sRGB, the color components are first converted |
| as if they are UNORM, and then sRGB to linear conversion is applied to the |
| R, G, and B components as described in the "`sRGB EOTF`" section of the |
| <<data-format,Khronos Data Format Specification>>. |
| The A component, if present, is unchanged. |
| |
| ifdef::VK_QCOM_ycbcr_degamma[] |
| [[textures-ycbcr-degamma]] |
| If |
| slink:VkSamplerYcbcrConversionYcbcrDegammaCreateInfoQCOM::pname:enableYDegamma |
| is equal to ename:VK_TRUE, then sRGB to linear conversion is applied to the |
| G component as described in the "`sRGB EOTF`" section of the |
| <<data-format,Khronos Data Format Specification>>. |
| If |
| slink:VkSamplerYcbcrConversionYcbcrDegammaCreateInfoQCOM::pname:enableCbCrDegamma |
| is equal to ename:VK_TRUE, then sRGB to linear conversion is applied to the |
| R and B components as described in the "`sRGB EOTF`" section of the |
| <<data-format,Khronos Data Format Specification>>. |
| The A component, if present, is unchanged. |
| endif::VK_QCOM_ycbcr_degamma[] |
| |
| If the image view format is block-compressed, then the texel value is first |
| decoded, then converted based on the type and number of components defined |
| by the compressed format. |
| |
| |
| [[textures-texel-replacement]] |
| === Texel Replacement |
| |
| A texel is replaced if it is one (and only one) of: |
| |
| * a border texel, |
| * an invalid texel, or |
| * a sparse unbound texel. |
| |
| Border texels are replaced with a value based on the image format and the |
| pname:borderColor of the sampler. |
| The border color is: |
| |
| [[textures-border-replacement-color]] |
| ifdef::VK_EXT_custom_border_color[] |
| .Border Color [eq]#B#, Custom Border Color slink:VkSamplerCustomBorderColorCreateInfoEXT::pname:customBorderColor [eq]#U# |
| endif::VK_EXT_custom_border_color[] |
| ifndef::VK_EXT_custom_border_color[] |
| .Border Color [eq]#B# |
| endif::VK_EXT_custom_border_color[] |
| [options="header",cols="60%,40%"] |
| |==== |
| | Sampler pname:borderColor | Corresponding Border Color |
| | ename:VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK | [eq]#[B~r~, B~g~, B~b~, B~a~] = [0.0, 0.0, 0.0, 0.0]# |
| | ename:VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK | [eq]#[B~r~, B~g~, B~b~, B~a~] = [0.0, 0.0, 0.0, 1.0]# |
| | ename:VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE | [eq]#[B~r~, B~g~, B~b~, B~a~] = [1.0, 1.0, 1.0, 1.0]# |
| | ename:VK_BORDER_COLOR_INT_TRANSPARENT_BLACK | [eq]#[B~r~, B~g~, B~b~, B~a~] = [0, 0, 0, 0]# |
| | ename:VK_BORDER_COLOR_INT_OPAQUE_BLACK | [eq]#[B~r~, B~g~, B~b~, B~a~] = [0, 0, 0, 1]# |
| | ename:VK_BORDER_COLOR_INT_OPAQUE_WHITE | [eq]#[B~r~, B~g~, B~b~, B~a~] = [1, 1, 1, 1]# |
| ifdef::VK_EXT_custom_border_color[] |
| | ename:VK_BORDER_COLOR_FLOAT_CUSTOM_EXT | [eq]#[B~r~, B~g~, B~b~, B~a~] = [U~r~, U~g~, U~b~, U~a~]# |
| | ename:VK_BORDER_COLOR_INT_CUSTOM_EXT | [eq]#[B~r~, B~g~, B~b~, B~a~] = [U~r~, U~g~, U~b~, U~a~]# |
| endif::VK_EXT_custom_border_color[] |
| |==== |
| |
| ifdef::VK_EXT_custom_border_color[] |
| The custom border color ([eq]#U#) may: be rounded by implementations prior |
| to texel replacement, but the error introduced by such a rounding must: not |
| exceed one ULP of the image's pname:format. |
| endif::VK_EXT_custom_border_color[] |
| |
| [NOTE] |
| .Note |
| ==== |
| The names etext:VK_BORDER_COLOR_*\_TRANSPARENT_BLACK, |
| etext:VK_BORDER_COLOR_*\_OPAQUE_BLACK, and |
| etext:VK_BORDER_COLOR_*_OPAQUE_WHITE are meant to describe which components |
| are zeros and ones in the vocabulary of compositing, and are not meant to |
| imply that the numerical value of ename:VK_BORDER_COLOR_INT_OPAQUE_WHITE is |
| a saturating value for integers. |
| ==== |
| |
| This is substituted for the texel value by replacing the number of |
| components in the image format |
| |
| [[textures-border-replacement-table]] |
| .Border Texel Components After Replacement |
| [width="100%",options="header"] |
| |==== |
| | Texel Aspect or Format | Component Assignment |
| | Depth aspect | [eq]#D = B~r~# |
| ifdef::VK_EXT_custom_border_color[] |
| | Stencil aspect | [eq]#S = B~r~#{sym2} |
| endif::VK_EXT_custom_border_color[] |
| ifndef::VK_EXT_custom_border_color[] |
| | Stencil aspect | [eq]#S = B~r~# |
| endif::VK_EXT_custom_border_color[] |
| | One component color format | [eq]#Color~r~ = B~r~# |
| | Two component color format | [eq]#[Color~r~,Color~g~] = [B~r~,B~g~]# |
| | Three component color format| [eq]#[Color~r~,Color~g~,Color~b~] = [B~r~,B~g~,B~b~]# |
| | Four component color format | [eq]#[Color~r~,Color~g~,Color~b~,Color~a~] = [B~r~,B~g~,B~b~,B~a~]# |
| ifdef::VK_KHR_maintenance5[] |
| | Single component alpha format | [eq]#[Color~r~,Color~g~,Color~b~, Color~a~] = [0,0,0,B~a~]# |
| endif::VK_KHR_maintenance5[] |
| |==== |
| ifdef::VK_EXT_custom_border_color[] |
| {sym2} [eq]#S = B~g~# may: be substituted as the replacement method by the |
| implementation when slink:VkSamplerCreateInfo::pname:borderColor is |
| ename:VK_BORDER_COLOR_INT_CUSTOM_EXT and |
| slink:VkSamplerCustomBorderColorCreateInfoEXT::pname:format is |
| ename:VK_FORMAT_UNDEFINED. |
| Implementations should: use [eq]#S = B~r~# as the replacement method. |
| endif::VK_EXT_custom_border_color[] |
| |
| The value returned by a read of an invalid texel is undefined:, unless that |
| read operation is from a buffer resource and the pname:robustBufferAccess |
| feature is enabled. |
| In that case, an invalid texel is replaced as described by the |
| <<features-robustBufferAccess, pname:robustBufferAccess>> feature. |
| ifdef::VK_VERSION_1_3,VK_EXT_image_robustness,VK_EXT_robustness2[] |
| If the access is to an image resource and the x, y, z, or layer coordinate |
| validation fails and |
| ifdef::VK_VERSION_1_3,VK_EXT_image_robustness[] |
| the <<features-robustImageAccess, pname:robustImageAccess>> feature is |
| enabled, then zero must: be returned for the R, G, and B components, if |
| present. |
| Either zero or one must: be returned for the A component, if present. |
| ifdef::VK_EXT_robustness2[If] |
| endif::VK_VERSION_1_3,VK_EXT_image_robustness[] |
| ifdef::VK_EXT_robustness2[] |
| If the <<features-robustImageAccess2, pname:robustImageAccess2>> feature is |
| enabled, zero values must: be returned. |
| endif::VK_EXT_robustness2[] |
| If only the sample index was invalid, the values returned are undefined:. |
| endif::VK_VERSION_1_3,VK_EXT_image_robustness,VK_EXT_robustness2[] |
| |
| ifdef::VK_VERSION_1_3,VK_EXT_image_robustness[] |
| Additionally, if the <<features-robustImageAccess, pname:robustImageAccess>> |
| feature is enabled, |
| ifdef::VK_EXT_robustness2[] |
| but the <<features-robustImageAccess2, pname:robustImageAccess2>> feature is |
| not, |
| endif::VK_EXT_robustness2[] |
| any invalid texels may: be expanded to four components prior to texel |
| replacement. |
| This means that components not present in the image format may be replaced |
| with 0 or may undergo <<textures-conversion-to-rgba,conversion to RGBA>> as |
| normal. |
| endif::VK_VERSION_1_3,VK_EXT_image_robustness[] |
| |
| ifdef::VK_EXT_robustness2[] |
| Loads from a null descriptor return a four component color value of all |
| zeros. |
| However, for storage images and storage texel buffers using an explicit |
| SPIR-V Image Format, loads from a null descriptor may: return an alpha value |
| of 1 (float or integer, depending on format) if the format does not include |
| alpha. |
| endif::VK_EXT_robustness2[] |
| |
| If the |
| slink:VkPhysicalDeviceSparseProperties::pname:residencyNonResidentStrict |
| property is ename:VK_TRUE, a sparse unbound texel is replaced with 0 or 0.0 |
| values for integer and floating-point components of the image format, |
| respectively. |
| |
| If pname:residencyNonResidentStrict is ename:VK_FALSE, the value of the |
| sparse unbound texel is undefined:. |
| |
| |
| [[textures-depth-compare-operation]] |
| === Depth Compare Operation |
| |
| If the image view has a depth/stencil format, the depth component is |
| selected by the pname:aspectMask, and the operation is an code:OpImage*Dref* |
| instruction, a depth comparison is performed. |
| The result is [eq]#1.0# if the comparison evaluates to [eq]#true#, and |
| [eq]#0.0# otherwise. |
| This value replaces the depth component [eq]#D#. |
| |
| The compare operation is selected by the elink:VkCompareOp value set by |
| slink:VkSamplerCreateInfo::pname:compareOp. |
| The reference value from the SPIR-V operand [eq]#D~ref~# and the texel depth |
| value [eq]#D~tex~# are used as the _reference_ and _test_ values, |
| respectively, in that operation. |
| |
| If the image being sampled has an unsigned normalized fixed-point format, |
| then [eq]#D~ref~# is clamped to [eq]#[0,1]# before the compare operation. |
| |
| |
| [[textures-conversion-to-rgba]] |
| === Conversion to RGBA |
| |
| The texel is expanded from one, two, or three components to four components |
| based on the image base color: |
| |
| [[textures-texel-color-rgba-conversion-table]] |
| .Texel Color After Conversion To RGBA |
| [width="100%", options="header", cols="<4,<6"] |
| |==== |
| | Texel Aspect or Format | RGBA Color |
| | Depth aspect | [eq]#[Color~r~,Color~g~,Color~b~, Color~a~] = [D,0,0,one]# |
| | Stencil aspect | [eq]#[Color~r~,Color~g~,Color~b~, Color~a~] = [S,0,0,one]# |
| | One component color format | [eq]#[Color~r~,Color~g~,Color~b~, Color~a~] = [Color~r~,0,0,one]# |
| | Two component color format | [eq]#[Color~r~,Color~g~,Color~b~, Color~a~] = [Color~r~,Color~g~,0,one]# |
| | Three component color format| [eq]#[Color~r~,Color~g~,Color~b~, Color~a~] = [Color~r~,Color~g~,Color~b~,one]# |
| | Four component color format | [eq]#[Color~r~,Color~g~,Color~b~, Color~a~] = [Color~r~,Color~g~,Color~b~,Color~a~]# |
| ifdef::VK_KHR_maintenance5[] |
| | One alpha component color format | [eq]#[Color~r~,Color~g~,Color~b~, Color~a~] = [0,0,0,Color~a~]# |
| endif::VK_KHR_maintenance5[] |
| |==== |
| |
| where [eq]#one = 1.0f# for floating-point formats and depth aspects, and |
| [eq]#one = 1# for integer formats and stencil aspects. |
| |
| |
| [[textures-component-swizzle]] |
| === Component Swizzle |
| |
| ifndef::VK_VERSION_1_1,VK_KHR_sampler_ycbcr_conversion[] |
| All texel input instructions apply a _swizzle_ based on the |
| elink:VkComponentSwizzle enums in the pname:components member of the |
| slink:VkImageViewCreateInfo structure for the image being read. |
| endif::VK_VERSION_1_1,VK_KHR_sampler_ycbcr_conversion[] |
| ifdef::VK_VERSION_1_1,VK_KHR_sampler_ycbcr_conversion[] |
| All texel input instructions apply a _swizzle_ based on: |
| |
| * the elink:VkComponentSwizzle enums in the pname:components member of the |
| slink:VkImageViewCreateInfo structure for the image being read if |
| <<samplers-YCbCr-conversion,sampler {YCbCr} conversion>> is not enabled, |
| and |
| * the elink:VkComponentSwizzle enums in the pname:components member of the |
| slink:VkSamplerYcbcrConversionCreateInfo structure for the |
| <<samplers-YCbCr-conversion,sampler {YCbCr} conversion>> if sampler |
| {YCbCr} conversion is enabled. |
| |
| endif::VK_VERSION_1_1,VK_KHR_sampler_ycbcr_conversion[] |
| |
| The swizzle can: rearrange the components of the texel, or substitute zero |
| or one for any components. |
| It is defined as follows for each color [eq]#component#: |
| |
| |
| [latexmath] |
| +++++++++++++++++++ |
| \begin{aligned} |
| Color'_{component} & = |
| \begin{cases} |
| Color_r & \text{for RED swizzle} \\ |
| Color_g & \text{for GREEN swizzle} \\ |
| Color_b & \text{for BLUE swizzle} \\ |
| Color_a & \text{for ALPHA swizzle} \\ |
| 0 & \text{for ZERO swizzle} \\ |
| one & \text{for ONE swizzle} \\ |
| identity & \text{for IDENTITY swizzle} |
| \end{cases} |
| \end{aligned} |
| +++++++++++++++++++ |
| |
| where: |
| |
| [latexmath] |
| +++++++++++++++++++ |
| \begin{aligned} |
| one & = |
| \begin{cases} |
| & 1.0\text{f} & \text{for floating point components} \\ |
| & 1 & \text{for integer components} \\ |
| \end{cases} |
| \\ |
| identity & = |
| \begin{cases} |
| & Color_r & \text{for}\ component = r \\ |
| & Color_g & \text{for}\ component = g \\ |
| & Color_b & \text{for}\ component = b \\ |
| & Color_a & \text{for}\ component = a \\ |
| \end{cases} |
| \end{aligned} |
| +++++++++++++++++++ |
| |
| If the border color is one of the etext:VK_BORDER_COLOR_*_OPAQUE_BLACK enums |
| and the elink:VkComponentSwizzle is not the |
| <<resources-image-views-identity-mappings,identity swizzle>> for all |
| components, the value of the texel after swizzle is undefined:. |
| |
| ifndef::VK_KHR_maintenance5[] |
| If the image view has a depth/stencil format and the |
| elink:VkComponentSwizzle is ename:VK_COMPONENT_SWIZZLE_ONE, the value of the |
| texel after swizzle is undefined:. |
| endif::VK_KHR_maintenance5[] |
| ifdef::VK_KHR_maintenance5[] |
| If the image view has a depth/stencil format and the |
| elink:VkComponentSwizzle is ename:VK_COMPONENT_SWIZZLE_ONE, and |
| sname:VkPhysicalDeviceMaintenance5PropertiesKHR::pname:depthStencilSwizzleOneSupport |
| is not set to ename:VK_TRUE, the value of the texel after swizzle is |
| undefined:. |
| endif::VK_KHR_maintenance5[] |
| |
| |
| [[textures-sparse-residency]] |
| === Sparse Residency |
| |
| code:OpImageSparse* instructions return a structure which includes a |
| _residency code_ indicating whether any texels accessed by the instruction |
| are sparse unbound texels. |
| This code can: be interpreted by the code:OpImageSparseTexelsResident |
| instruction which converts the residency code to a boolean value. |
| |
| |
| ifdef::VK_VERSION_1_1,VK_KHR_sampler_ycbcr_conversion[] |
| [[textures-chroma-reconstruction]] |
| === Chroma Reconstruction |
| |
| In some color models, the color representation is defined in terms of |
| monochromatic light intensity (often called "`luma`") and color differences |
| relative to this intensity, often called "`chroma`". |
| It is common for color models other than RGB to represent the chroma |
| components at lower spatial resolution than the luma component. |
| This approach is used to take advantage of the eye's lower spatial |
| sensitivity to color compared with its sensitivity to brightness. |
| Less commonly, the same approach is used with additive color, since the |
| green component dominates the eye's sensitivity to light intensity and the |
| spatial sensitivity to color introduced by red and blue is lower. |
| |
| Lower-resolution components are "`downsampled`" by resizing them to a lower |
| spatial resolution than the component representing luminance. |
| This process is also commonly known as "`chroma subsampling`". |
| There is one luminance sample in each texture texel, but each chrominance |
| sample may be shared among several texels in one or both texture dimensions. |
| |
| * "`etext:_444`" formats do not spatially downsample chroma values |
| compared with luma: there are unique chroma samples for each texel. |
| * "`etext:_422`" formats have downsampling in the x dimension |
| (corresponding to _u_ or _s_ coordinates): they are sampled at half the |
| resolution of luma in that dimension. |
| * "`etext:_420`" formats have downsampling in the x dimension |
| (corresponding to _u_ or _s_ coordinates) and the y dimension |
| (corresponding to _v_ or _t_ coordinates): they are sampled at half the |
| resolution of luma in both dimensions. |
| |
| The process of reconstructing a full color value for texture access involves |
| accessing both chroma and luma values at the same location. |
| To generate the color accurately, the values of the lower-resolution |
| components at the location of the luma samples must be reconstructed from |
| the lower-resolution sample locations, an operation known here as "`chroma |
| reconstruction`" irrespective of the actual color model. |
| |
| The location of the chroma samples relative to the luma coordinates is |
| determined by the pname:xChromaOffset and pname:yChromaOffset members of the |
| slink:VkSamplerYcbcrConversionCreateInfo structure used to create the |
| sampler {YCbCr} conversion. |
| |
| The following diagrams show the relationship between unnormalized (_u_,_v_) |
| coordinates and (_i_,_j_) integer texel positions in the luma component |
| (shown in black, with circles showing integer sample positions) and the |
| texel coordinates of reduced-resolution chroma components, shown as crosses |
| in red. |
| |
| [NOTE] |
| .Note |
| ==== |
| If the chroma values are reconstructed at the locations of the luma samples |
| by means of interpolation, chroma samples from outside the image bounds are |
| needed; these are determined according to <<textures-wrapping-operation>>. |
| These diagrams represent this by showing the bounds of the "`chroma texel`" |
| extending beyond the image bounds, and including additional chroma sample |
| positions where required for interpolation. |
| The limits of a sample for etext:NEAREST sampling is shown as a grid. |
| ==== |
| |
| image::{images}/chromasamples_422_cosited.svg[align="center",title="422 downsampling, xChromaOffset=COSITED_EVEN",opts="{imageopts}"] |
| |
| image::{images}/chromasamples_422_midpoint.svg[align="center",title="422 downsampling, xChromaOffset=MIDPOINT",opts="{imageopts}"] |
| |
| image::{images}/chromasamples_420_xcosited_ycosited.svg[align="center",title="420 downsampling, xChromaOffset=COSITED_EVEN, yChromaOffset=COSITED_EVEN",opts="{imageopts}"] |
| |
| image::{images}/chromasamples_420_xmidpoint_ycosited.svg[align="center",title="420 downsampling, xChromaOffset=MIDPOINT, yChromaOffset=COSITED_EVEN",opts="{imageopts}"] |
| |
| image::{images}/chromasamples_420_xcosited_ymidpoint.svg[align="center",title="420 downsampling, xChromaOffset=COSITED_EVEN, yChromaOffset=MIDPOINT",opts="{imageopts}"] |
| |
| image::{images}/chromasamples_420_xmidpoint_ymidpoint.svg[align="center",title="420 downsampling, xChromaOffset=MIDPOINT, yChromaOffset=MIDPOINT",opts="{imageopts}"] |
| |
| Reconstruction is implemented in one of two ways: |
| |
| If the format of the image that is to be sampled sets |
| ename:VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT, |
| or the slink:VkSamplerYcbcrConversionCreateInfo's |
| pname:forceExplicitReconstruction is set to ename:VK_TRUE, reconstruction is |
| performed as an explicit step independent of filtering, described in the |
| <<textures-explicit-reconstruction>> section. |
| |
| If the format of the image that is to be sampled does not set |
| ename:VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT |
| and if the slink:VkSamplerYcbcrConversionCreateInfo's |
| pname:forceExplicitReconstruction is set to ename:VK_FALSE, reconstruction |
| is performed as an implicit part of filtering prior to color model |
| conversion, with no separate post-conversion texel filtering step, as |
| described in the <<textures-implict-reconstruction,Implicit Reconstruction>> |
| section. |
| |
| |
| [[textures-explicit-reconstruction]] |
| ==== Explicit Reconstruction |
| |
| * If the pname:chromaFilter member of the |
| slink:VkSamplerYcbcrConversionCreateInfo structure is |
| ename:VK_FILTER_NEAREST: |
| ** If the format's R and B components are reduced in resolution in just |
| width by a factor of two relative to the G component (i.e. this is a |
| "`etext:_422`" format), the latexmath:[\tau_{ijk}[level\]] values |
| accessed by <<textures-texel-filtering,texel filtering>> are |
| reconstructed as follows: |
| + |
| [latexmath] |
| ++++++++++++++ |
| \begin{aligned} |
| \tau_R'(i, j) & = \tau_R(\left\lfloor{i\times 0.5}\right\rfloor, j)[level] \\ |
| \tau_B'(i, j) & = \tau_B(\left\lfloor{i\times 0.5}\right\rfloor, j)[level] |
| \end{aligned} |
| ++++++++++++++ |
| |
| ** If the format's R and B components are reduced in resolution in width |
| and height by a factor of two relative to the G component (i.e. this is |
| a "`etext:_420`" format), the latexmath:[\tau_{ijk}[level\]] values |
| accessed by <<textures-texel-filtering,texel filtering>> are |
| reconstructed as follows: |
| + |
| [latexmath] |
| ++++++++++++++ |
| \begin{aligned} |
| \tau_R'(i, j) & = \tau_R(\left\lfloor{i\times 0.5}\right\rfloor, \left\lfloor{j\times 0.5}\right\rfloor)[level] \\ |
| \tau_B'(i, j) & = \tau_B(\left\lfloor{i\times 0.5}\right\rfloor, \left\lfloor{j\times 0.5}\right\rfloor)[level] |
| \end{aligned} |
| ++++++++++++++ |
| + |
| [NOTE] |
| .Note |
| ==== |
| pname:xChromaOffset and pname:yChromaOffset have no effect if |
| pname:chromaFilter is ename:VK_FILTER_NEAREST for explicit reconstruction. |
| ==== |
| |
| * If the pname:chromaFilter member of the |
| slink:VkSamplerYcbcrConversionCreateInfo structure is |
| ename:VK_FILTER_LINEAR: |
| ** If the format's R and B components are reduced in resolution in just |
| width by a factor of two relative to the G component (i.e. this is a |
| "`etext:_422`" format): |
| *** If pname:xChromaOffset is ename:VK_CHROMA_LOCATION_COSITED_EVEN: |
| + |
| [latexmath] |
| +++++ |
| \tau_{RB}'(i,j) = \begin{cases} |
| \tau_{RB}(\left\lfloor{i\times 0.5}\right\rfloor,j)[level], & 0.5 \times i = \left\lfloor{0.5 \times i}\right\rfloor\\ |
| 0.5\times\tau_{RB}(\left\lfloor{i\times 0.5}\right\rfloor,j)[level] + \\ |
| 0.5\times\tau_{RB}(\left\lfloor{i\times 0.5}\right\rfloor + 1,j)[level], & 0.5 \times i \neq \left\lfloor{0.5 \times i}\right\rfloor |
| \end{cases} |
| +++++ |
| + |
| *** If pname:xChromaOffset is ename:VK_CHROMA_LOCATION_MIDPOINT: |
| + |
| [latexmath] |
| +++++ |
| \tau_{RB}'(i,j) = \begin{cases} |
| 0.25 \times \tau_{RB}(\left\lfloor{i\times 0.5}\right\rfloor - 1,j)[level] + \\ |
| 0.75 \times \tau_{RB}(\left\lfloor{i\times 0.5}\right\rfloor,j)[level], & 0.5 \times i = \left\lfloor{0.5 \times i}\right\rfloor\\ |
| 0.75 \times \tau_{RB}(\left\lfloor{i\times 0.5}\right\rfloor,j)[level] + \\ |
| 0.25 \times \tau_{RB}(\left\lfloor{i\times 0.5}\right\rfloor + 1,j)[level], & 0.5 \times i \neq \left\lfloor{0.5 \times i}\right\rfloor |
| \end{cases} |
| +++++ |
| |
| ** If the format's R and B components are reduced in resolution in width |
| and height by a factor of two relative to the G component (i.e. this is |
| a "`etext:_420`" format), a similar relationship applies. |
| Due to the number of options, these formulae are expressed more |
| concisely as follows: |
| + |
| [latexmath] |
| +++++ |
| \begin{aligned} |
| i_{RB} & = |
| \begin{cases} |
| 0.5 \times (i) & \textrm{xChromaOffset = COSITED}\_\textrm{EVEN} \\ |
| 0.5 \times (i - 0.5) & \textrm{xChromaOffset = MIDPOINT} |
| \end{cases}\\ |
| j_{RB} & = |
| \begin{cases} |
| 0.5 \times (j) & \textrm{yChromaOffset = COSITED}\_\textrm{EVEN} \\ |
| 0.5 \times (j - 0.5) & \textrm{yChromaOffset = MIDPOINT} |
| \end{cases}\\ |
| \\ |
| i_{floor} & = \left\lfloor i_{RB} \right\rfloor \\ |
| j_{floor} & = \left\lfloor j_{RB} \right\rfloor \\ |
| \\ |
| i_{frac} & = i_{RB} - i_{floor} \\ |
| j_{frac} & = j_{RB} - j_{floor} |
| \end{aligned} |
| +++++ |
| + |
| [latexmath] |
| +++++ |
| \begin{aligned} |
| \tau_{RB}'(i,j) = |
| & \tau_{RB}( i_{floor}, j_{floor})[level] |
| & \times & ( 1 - i_{frac} ) & |
| & \times & ( 1 - j_{frac} ) & + \\ |
| & \tau_{RB}( 1 + i_{floor}, j_{floor})[level] |
| & \times & ( i_{frac} ) & |
| & \times & ( 1 - j_{frac} ) & + \\ |
| & \tau_{RB}( i_{floor}, 1 + j_{floor})[level] |
| & \times & ( 1 - i_{frac} ) & |
| & \times & ( j_{frac} ) & + \\ |
| & \tau_{RB}( 1 + i_{floor}, 1 + j_{floor})[level] |
| & \times & ( i_{frac} ) & |
| & \times & ( j_{frac} ) & |
| \end{aligned} |
| +++++ |
| |
| [NOTE] |
| .Note |
| ==== |
| In the case where the texture itself is bilinearly interpolated as described |
| in <<textures-texel-filtering,Texel Filtering>>, thus requiring four |
| full-color samples for the filtering operation, and where the reconstruction |
| of these samples uses bilinear interpolation in the chroma components due to |
| pname:chromaFilter=ename:VK_FILTER_LINEAR, up to nine chroma samples may be |
| required, depending on the sample location. |
| ==== |
| |
| |
| [[textures-implict-reconstruction]] |
| ==== Implicit Reconstruction |
| |
| Implicit reconstruction takes place by the samples being interpolated, as |
| required by the filter settings of the sampler, except that |
| pname:chromaFilter takes precedence for the chroma samples. |
| |
| If pname:chromaFilter is ename:VK_FILTER_NEAREST, an implementation may: |
| behave as if pname:xChromaOffset and pname:yChromaOffset were both |
| ename:VK_CHROMA_LOCATION_MIDPOINT, irrespective of the values set. |
| |
| [NOTE] |
| .Note |
| ==== |
| This will not have any visible effect if the locations of the luma samples |
| coincide with the location of the samples used for rasterization. |
| ==== |
| |
| The sample coordinates are adjusted by the downsample factor of the |
| component (such that, for example, the sample coordinates are divided by two |
| if the component has a downsample factor of two relative to the luma |
| component): |
| |
| [latexmath] |
| ++++++ |
| \begin{aligned} |
| u_{RB}' (422/420) &= |
| \begin{cases} |
| 0.5\times (u + 0.5), & \textrm{xChromaOffset = COSITED}\_\textrm{EVEN} \\ |
| 0.5\times u, & \textrm{xChromaOffset = MIDPOINT} |
| \end{cases} \\ |
| v_{RB}' (420) &= |
| \begin{cases} |
| 0.5\times (v + 0.5), & \textrm{yChromaOffset = COSITED}\_\textrm{EVEN} \\ |
| 0.5\times v, & \textrm{yChromaOffset = MIDPOINT} |
| \end{cases} |
| \end{aligned} |
| ++++++ |
| |
| |
| [[textures-sampler-YCbCr-conversion]] |
| === Sampler {YCbCr} Conversion |
| |
| Sampler {YCbCr} conversion performs the following operations, which an |
| implementation may: combine into a single mathematical operation: |
| |
| * <<textures-sampler-YCbCr-conversion-rangeexpand,Sampler {YCbCr} Range |
| Expansion>> |
| * <<textures-sampler-YCbCr-conversion-modelconversion,Sampler {YCbCr} |
| Model Conversion>> |
| |
| |
| [[textures-sampler-YCbCr-conversion-rangeexpand]] |
| ==== Sampler {YCbCr} Range Expansion |
| |
| Sampler {YCbCr} range expansion is applied to color component values after |
| all texel input operations which are not specific to sampler {YCbCr} |
| conversion. |
| For example, the input values to this stage have been converted using the |
| normal <<textures-format-conversion,format conversion>> rules. |
| |
| ifdef::VK_QCOM_ycbcr_degamma[] |
| The input values to this stage may have been converted using sRGB to linear |
| conversion if <<features-ycbcr-degamma,pname:ycbcrDegamma>> is enabled. |
| endif::VK_QCOM_ycbcr_degamma[] |
| |
| Sampler {YCbCr} range expansion is not applied if pname:ycbcrModel is |
| ename:VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY. |
| That is, the shader receives the vector C'~rgba~ as output by the Component |
| Swizzle stage without further modification. |
| |
| For other values of pname:ycbcrModel, range expansion is applied to the |
| texel component values output by the <<textures-component-swizzle,Component |
| Swizzle>> defined by the pname:components member of |
| slink:VkSamplerYcbcrConversionCreateInfo. |
| Range expansion applies independently to each component of the image. |
| For the purposes of range expansion and {YCbCr} model conversion, the R and |
| B components contain color difference (chroma) values and the G component |
| contains luma. |
| The A component is not modified by sampler {YCbCr} range expansion. |
| |
| The range expansion to be applied is defined by the pname:ycbcrRange member |
| of the slink:VkSamplerYcbcrConversionCreateInfo structure: |
| |
| * If pname:ycbcrRange is ename:VK_SAMPLER_YCBCR_RANGE_ITU_FULL, the |
| following transformations are applied: |
| + |
| [latexmath] |
| +++++++++++++++++++ |
| \begin{aligned} |
| Y' &= C'_{rgba}[G] \\ |
| C_B &= C'_{rgba}[B] - {{2^{(n-1)}}\over{(2^n) - 1}} \\ |
| C_R &= C'_{rgba}[R] - {{2^{(n-1)}}\over{(2^n) - 1}} |
| \end{aligned} |
| +++++++++++++++++++ |
| + |
| [NOTE] |
| .Note |
| ==== |
| These formulae correspond to the "`full range`" encoding in the |
| "`Quantization schemes`" chapter of the <<data-format,Khronos Data Format |
| Specification>>. |
| |
| Should any future amendments be made to the ITU specifications from which |
| these equations are derived, the formulae used by Vulkan may: also be |
| updated to maintain parity. |
| ==== |
| * If pname:ycbcrRange is ename:VK_SAMPLER_YCBCR_RANGE_ITU_NARROW, the |
| following transformations are applied: |
| + |
| [latexmath] |
| +++++++++++++++++++ |
| \begin{aligned} |
| Y' &= {{C'_{rgba}[G] \times (2^n-1) - 16\times 2^{n-8}}\over{219\times 2^{n-8}}} \\ |
| C_B &= {{C'_{rgba}[B] \times \left(2^n-1\right) - 128\times 2^{n-8}}\over{224\times 2^{n-8}}} \\ |
| C_R &= {{C'_{rgba}[R] \times \left(2^n-1\right) - 128\times 2^{n-8}}\over{224\times 2^{n-8}}} |
| \end{aligned} |
| +++++++++++++++++++ |
| + |
| [NOTE] |
| .Note |
| ==== |
| These formulae correspond to the "`narrow range`" encoding in the |
| "`Quantization schemes`" chapter of the <<data-format,Khronos Data Format |
| Specification>>. |
| ==== |
| * _n_ is the bit-depth of the components in the format. |
| |
| The precision of the operations performed during range expansion must: be at |
| least that of the source format. |
| |
| An implementation may: clamp the results of these range expansion operations |
| such that Y{prime} falls in the range [0,1], and/or such that C~B~ and C~R~ |
| fall in the range [-0.5,0.5]. |
| |
| |
| [[textures-sampler-YCbCr-conversion-modelconversion]] |
| ==== Sampler {YCbCr} Model Conversion |
| |
| The range-expanded values are converted between color models, according to |
| the color model conversion specified in the pname:ycbcrModel member: |
| |
| ename:VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY:: |
| The color components are not modified by the color model conversion |
| since they are assumed already to represent the desired color model in |
| which the shader is operating; {YCbCr} range expansion is also ignored. |
| ename:VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY:: |
| The color components are not modified by the color model conversion and |
| are assumed to be treated as though in {YCbCr} form both in memory and |
| in the shader; {YCbCr} range expansion is applied to the components as |
| for other {YCbCr} models, with the vector (C~R~,Y{prime},C~B~,A) |
| provided to the shader. |
| ename:VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709:: |
| The color components are transformed from a {YCbCr} representation to an |
| {RGBprime} representation as described in the "`BT.709 {YCbCr} |
| conversion`" section of the <<data-format,Khronos Data Format |
| Specification>>. |
| ename:VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601:: |
| The color components are transformed from a {YCbCr} representation to an |
| {RGBprime} representation as described in the "`BT.601 {YCbCr} |
| conversion`" section of the <<data-format,Khronos Data Format |
| Specification>>. |
| ename:VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020:: |
| The color components are transformed from a {YCbCr} representation to an |
| {RGBprime} representation as described in the "`BT.2020 {YCbCr} |
| conversion`" section of the <<data-format,Khronos Data Format |
| Specification>>. |
| |
| In this operation, each output component is dependent on each input |
| component. |
| |
| An implementation may: clamp the {RGBprime} results of these conversions to |
| the range [0,1]. |
| |
| The precision of the operations performed during model conversion must: be |
| at least that of the source format. |
| |
| The alpha component is not modified by these model conversions. |
| |
| [NOTE] |
| .Note |
| ==== |
| Sampling operations in a non-linear color space can introduce color and |
| intensity shifts at sharp transition boundaries. |
| To avoid this issue, the technically precise color correction sequence |
| described in the "`Introduction to Color Conversions`" chapter of the |
| <<data-format,Khronos Data Format Specification>> may be performed as |
| follows: |
| |
| * Calculate the <<textures-normalized-to-unnormalized,unnormalized texel |
| coordinates>> corresponding to the desired sample position. |
| * For a pname:minFilter or pname:magFilter of ename:VK_FILTER_NEAREST: |
| . Calculate (_i_,_j_) for the sample location as described under the |
| "`nearest filtering`" formulae in <<textures-unnormalized-to-integer>> |
| . Calculate the normalized texel coordinates corresponding to these |
| integer coordinates. |
| . Sample using <<samplers-YCbCr-conversion,sampler {YCbCr} conversion>> |
| at this location. |
| * For a pname:minFilter or pname:magFilter of ename:VK_FILTER_LINEAR: |
| . Calculate (_i~[0,1]~_,_j~[0,1]~_) for the sample location as described |
| under the "`linear filtering`" formulae in |
| <<textures-unnormalized-to-integer>> |
| . Calculate the normalized texel coordinates corresponding to these |
| integer coordinates. |
| . Sample using <<samplers-YCbCr-conversion,sampler {YCbCr} conversion>> |
| at each of these locations. |
| . Convert the non-linear A{prime}{RGBprime} outputs of the {YCbCr} |
| conversions to linear ARGB values as described in the "`Transfer |
| Functions`" chapter of the <<data-format,Khronos Data Format |
| Specification>>. |
| . Interpolate the linear ARGB values using the [eq]#{alpha}# and |
| [eq]#{beta}# values described in the "`linear filtering`" section of |
| <<textures-unnormalized-to-integer>> and the equations in |
| <<textures-texel-filtering>>. |
| |
| The additional calculations and, especially, additional number of sampling |
| operations in the ename:VK_FILTER_LINEAR case can be expected to have a |
| performance impact compared with using the outputs directly. |
| Since the variations from "`correct`" results are subtle for most content, |
| the application author should determine whether a more costly implementation |
| is strictly necessary. |
| |
| If pname:chromaFilter, and pname:minFilter or pname:magFilter are both |
| ename:VK_FILTER_NEAREST, these operations are redundant and sampling using |
| <<samplers-YCbCr-conversion,sampler {YCbCr} conversion>> at the desired |
| sample coordinates will produce the "`correct`" results without further |
| processing. |
| ==== |
| endif::VK_VERSION_1_1,VK_KHR_sampler_ycbcr_conversion[] |
| |
| |
| == Texel Output Operations |
| |
| _Texel output instructions_ are SPIR-V image instructions that write to an |
| image. |
| _Texel output operations_ are a set of steps that are performed on state, |
| coordinates, and texel values while processing a texel output instruction, |
| and which are common to some or all texel output instructions. |
| They include the following steps, which are performed in the listed order: |
| |
| * <<textures-output-validation,Validation operations>> |
| ** <<textures-format-validation,Format validation>> |
| ** <<textures-type-validation,Type validation>> |
| ** <<textures-output-coordinate-validation,Coordinate validation>> |
| ** <<textures-output-sparse-validation,Sparse validation>> |
| * <<textures-output-format-conversion,Texel output format conversion>> |
| |
| |
| [[textures-output-validation]] |
| === Texel Output Validation Operations |
| |
| _Texel output validation operations_ inspect instruction/image state or |
| coordinates, and in certain circumstances cause the write to have no effect. |
| There are a series of validations that the texel undergoes. |
| |
| |
| [[textures-format-validation]] |
| ==== Texel Format Validation |
| |
| If the image format of the code:OpTypeImage is not |
| <<spirvenv-image-formats,compatible>> with the sname:VkImageView's |
| pname:format, the write causes the contents of the image's memory to become |
| undefined:. |
| |
| |
| [[textures-type-validation]] |
| ==== Texel Type Validation |
| |
| If the code:Sampled code:Type of the code:OpTypeImage does not match the |
| <<spirv-type,SPIR-V Type>>, the write causes the value of the texel to |
| become undefined:. |
| For integer types, if the <<spirvenv-image-signedness,signedness of the |
| access>> does not match the signedness of the accessed resource, the write |
| causes the value of the texel to become undefined:. |
| |
| |
| [[textures-output-coordinate-validation]] |
| === Integer Texel Coordinate Validation |
| |
| The integer texel coordinates are validated according to the same rules as |
| for texel input <<textures-integer-coordinate-validation,coordinate |
| validation>>. |
| |
| If the texel fails integer texel coordinate validation, then the write has |
| no effect. |
| |
| |
| [[textures-output-sparse-validation]] |
| === Sparse Texel Operation |
| |
| If the texel attempts to write to an unbound region of a sparse image, the |
| texel is a sparse unbound texel. |
| In such a case, if the |
| slink:VkPhysicalDeviceSparseProperties::pname:residencyNonResidentStrict |
| property is ename:VK_TRUE, the sparse unbound texel write has no effect. |
| If pname:residencyNonResidentStrict is ename:VK_FALSE, the write may: have a |
| side effect that becomes visible to other accesses to unbound texels in any |
| resource, but will not be visible to any device memory allocated by the |
| application. |
| |
| |
| [[textures-output-format-conversion]] |
| === Texel Output Format Conversion |
| |
| If the image format is sRGB, a linear to sRGB conversion is applied to the |
| R, G, and B components as described in the "`sRGB EOTF`" section of the |
| <<data-format,Khronos Data Format Specification>>. |
| The A component, if present, is unchanged. |
| |
| Texels then undergo a format conversion from the floating point, signed, or |
| unsigned integer type of the texel data to the elink:VkFormat of the image |
| view. |
| If the number of components in the texel data is larger than the number of |
| components in the format, additional components are discarded. |
| |
| Each component is converted based on its type and size (as defined in the |
| <<formats-definition,Format Definition>> section for each elink:VkFormat). |
| Floating-point outputs are converted as described in |
| <<fundamentals-fp-conversion,Floating-Point Format Conversions>> and |
| <<fundamentals-fixedconv,Fixed-Point Data Conversion>>. |
| Integer outputs are converted such that their value is preserved. |
| The converted value of any integer that cannot be represented in the target |
| format is undefined:. |
| |
| |
| [[textures-normalized-operations]] |
| == Normalized Texel Coordinate Operations |
| |
| If the image sampler instruction provides normalized texel coordinates, some |
| of the following operations are performed. |
| |
| |
| [[textures-projection]] |
| === Projection Operation |
| |
| For code:Proj image operations, the normalized texel coordinates |
| [eq]#(s,t,r,q,a)# and (if present) the [eq]#D~ref~# coordinate are |
| transformed as follows: |
| |
| [latexmath] |
| +++++++++++++++++++ |
| \begin{aligned} |
| s & = \frac{s}{q}, & \text{for 1D, 2D, or 3D image} \\ |
| \\ |
| t & = \frac{t}{q}, & \text{for 2D or 3D image} \\ |
| \\ |
| r & = \frac{r}{q}, & \text{for 3D image} \\ |
| \\ |
| D_{\textit{ref}} & = \frac{D_{\textit{ref}}}{q}, & \text{if provided} |
| \end{aligned} |
| +++++++++++++++++++ |
| |
| |
| [[textures-derivative-image-operations]] |
| === Derivative Image Operations |
| |
| Derivatives are used for LOD selection. |
| These derivatives are either implicit (in an code:ImplicitLod image |
| instruction in a fragment shader) or explicit (provided explicitly by shader |
| to the image instruction in any shader). |
| |
| For implicit derivatives image instructions, the derivatives of texel |
| coordinates are calculated in the same manner as |
| <<shaders-derivative-operations, derivative operations>>. |
| That is: |
| |
| [latexmath] |
| +++++++++++++++++++ |
| \begin{aligned} |
| \partial{s}/\partial{x} & = dPdx(s), & \partial{s}/\partial{y} & = dPdy(s), & \text{for 1D, 2D, Cube, or 3D image} \\ |
| \partial{t}/\partial{x} & = dPdx(t), & \partial{t}/\partial{y} & = dPdy(t), & \text{for 2D, Cube, or 3D image} \\ |
| \partial{r}/\partial{x} & = dPdx(r), & \partial{r}/\partial{y} & = dPdy(r), & \text{for Cube or 3D image} |
| \end{aligned} |
| +++++++++++++++++++ |
| |
| Partial derivatives not defined above for certain image dimensionalities are |
| set to zero. |
| |
| For explicit LOD image instructions, if the optional: SPIR-V operand |
| code:Grad is provided, then the operand values are used for the derivatives. |
| The number of components present in each derivative for a given image |
| dimensionality matches the number of partial derivatives computed above. |
| |
| If the optional: SPIR-V operand code:Lod is provided, then derivatives are |
| set to zero, the cube map derivative transformation is skipped, and the |
| scale factor operation is skipped. |
| Instead, the floating point scalar coordinate is directly assigned to |
| [eq]#{lambda}~base~# as described in <<textures-level-of-detail-operation, |
| LOD Operation>>. |
| |
| ifdef::VK_VERSION_1_2,VK_EXT_descriptor_indexing[] |
| If the image or sampler object used by an implicit derivative image |
| instruction is not uniform across the quad and |
| <<limits-quadDivergentImplicitLod, pname:quadDivergentImplicitLod>> is not |
| supported, then the derivative and LOD values are undefined:. |
| Implicit derivatives are well-defined when the image and sampler and control |
| flow are uniform across the quad, even if they diverge between different |
| quads. |
| |
| If <<limits-quadDivergentImplicitLod, pname:quadDivergentImplicitLod>> is |
| supported, then derivatives and implicit LOD values are well-defined even if |
| the image or sampler object are not uniform within a quad. |
| The derivatives are computed as specified above, and the implicit LOD |
| calculation proceeds for each shader invocation using its respective image |
| and sampler object. |
| endif::VK_VERSION_1_2,VK_EXT_descriptor_indexing[] |
| |
| |
| === Cube Map Face Selection and Transformations |
| |
| For cube map image instructions, the [eq]#(s,t,r)# coordinates are treated |
| as a direction vector [eq]#(r~x~,r~y~,r~z~)#. |
| The direction vector is used to select a cube map face. |
| The direction vector is transformed to a per-face texel coordinate system |
| [eq]#(s~face~,t~face~)#, The direction vector is also used to transform the |
| derivatives to per-face derivatives. |
| |
| |
| === Cube Map Face Selection |
| |
| The direction vector selects one of the cube map's faces based on the |
| largest magnitude coordinate direction (the major axis direction). |
| Since two or more coordinates can: have identical magnitude, the |
| implementation must: have rules to disambiguate this situation. |
| |
| The rules should: have as the first rule that [eq]#r~z~# wins over |
| [eq]#r~y~# and [eq]#r~x~#, and the second rule that [eq]#r~y~# wins over |
| [eq]#r~x~#. |
| An implementation may: choose other rules, but the rules must: be |
| deterministic and depend only on [eq]#(r~x~,r~y~,r~z~)#. |
| |
| The layer number (corresponding to a cube map face), the coordinate |
| selections for [eq]#s~c~#, [eq]#t~c~#, [eq]#r~c~#, and the selection of |
| derivatives, are determined by the major axis direction as specified in the |
| following two tables. |
| |
| .Cube map face and coordinate selection |
| [width="75%",frame="all",options="header"] |
| |==== |
| | Major Axis Direction | Layer Number | Cube Map Face | [eq]#s~c~# | [eq]#t~c~# | [eq]#r~c~# |
| | [eq]#+r~x~# | [eq]#0# | Positive X | [eq]#-r~z~# | [eq]#-r~y~# | [eq]#r~x~# |
| | [eq]#-r~x~# | [eq]#1# | Negative X | [eq]#+r~z~# | [eq]#-r~y~# | [eq]#r~x~# |
| | [eq]#+r~y~# | [eq]#2# | Positive Y | [eq]#+r~x~# | [eq]#+r~z~# | [eq]#r~y~# |
| | [eq]#-r~y~# | [eq]#3# | Negative Y | [eq]#+r~x~# | [eq]#-r~z~# | [eq]#r~y~# |
| | [eq]#+r~z~# | [eq]#4# | Positive Z | [eq]#+r~x~# | [eq]#-r~y~# | [eq]#r~z~# |
| | [eq]#-r~z~# | [eq]#5# | Negative Z | [eq]#-r~x~# | [eq]#-r~y~# | [eq]#r~z~# |
| |==== |
| |
| |
| .Cube map derivative selection |
| [width="75%",frame="all",options="header"] |
| |==== |
| | Major Axis Direction | [eq]#{partial}s~c~ / {partial}x# | [eq]#{partial}s~c~ / {partial}y# | [eq]#{partial}t~c~ / {partial}x# | [eq]#{partial}t~c~ / {partial}y# | [eq]#{partial}r~c~ / {partial}x# | [eq]#{partial}r~c~ / {partial}y# |
| |
| | [eq]#+r~x~# |
| | [eq]#-{partial}r~z~ / {partial}x# | [eq]#-{partial}r~z~ / {partial}y# |
| | [eq]#-{partial}r~y~ / {partial}x# | [eq]#-{partial}r~y~ / {partial}y# |
| | [eq]#+{partial}r~x~ / {partial}x# | [eq]#+{partial}r~x~ / {partial}y# |
| |
| | [eq]#-r~x~# |
| | [eq]#+{partial}r~z~ / {partial}x# | [eq]#+{partial}r~z~ / {partial}y# |
| | [eq]#-{partial}r~y~ / {partial}x# | [eq]#-{partial}r~y~ / {partial}y# |
| | [eq]#-{partial}r~x~ / {partial}x# | [eq]#-{partial}r~x~ / {partial}y# |
| |
| | [eq]#+r~y~# |
| | [eq]#+{partial}r~x~ / {partial}x# | [eq]#+{partial}r~x~ / {partial}y# |
| | [eq]#+{partial}r~z~ / {partial}x# | [eq]#+{partial}r~z~ / {partial}y# |
| | [eq]#+{partial}r~y~ / {partial}x# | [eq]#+{partial}r~y~ / {partial}y# |
| |
| | [eq]#-r~y~# |
| | [eq]#+{partial}r~x~ / {partial}x# | [eq]#+{partial}r~x~ / {partial}y# |
| | [eq]#-{partial}r~z~ / {partial}x# | [eq]#-{partial}r~z~ / {partial}y# |
| | [eq]#-{partial}r~y~ / {partial}x# | [eq]#-{partial}r~y~ / {partial}y# |
| |
| | [eq]#+r~z~# |
| | [eq]#+{partial}r~x~ / {partial}x# | [eq]#+{partial}r~x~ / {partial}y# |
| | [eq]#-{partial}r~y~ / {partial}x# | [eq]#-{partial}r~y~ / {partial}y# |
| | [eq]#+{partial}r~z~ / {partial}x# | [eq]#+{partial}r~z~ / {partial}y# |
| |
| | [eq]#-r~z~# |
| | [eq]#-{partial}r~x~ / {partial}x# | [eq]#-{partial}r~x~ / {partial}y# |
| | [eq]#-{partial}r~y~ / {partial}x# | [eq]#-{partial}r~y~ / {partial}y# |
| | [eq]#-{partial}r~z~ / {partial}x# | [eq]#-{partial}r~z~ / {partial}y# |
| |==== |
| |
| |
| === Cube Map Coordinate Transformation |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| s_{\textit{face}} & = |
| \frac{1}{2} \times \frac{s_c}{|r_c|} + \frac{1}{2} \\ |
| t_{\textit{face}} & = |
| \frac{1}{2} \times \frac{t_c}{|r_c|} + \frac{1}{2} \\ |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| |
| === Cube Map Derivative Transformation |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \frac{\partial{s_{\textit{face}}}}{\partial{x}} &= |
| \frac{\partial}{\partial{x}} \left ( \frac{1}{2} \times \frac{s_{c}}{|r_{c}|} |
| + \frac{1}{2}\right ) \\ |
| \frac{\partial{s_{\textit{face}}}}{\partial{x}} &= |
| \frac{1}{2} \times \frac{\partial}{\partial{x}} |
| \left ( \frac{s_{c}}{|r_{c}|} \right ) \\ |
| \frac{\partial{s_{\textit{face}}}}{\partial{x}} &= |
| \frac{1}{2} \times |
| \left ( |
| \frac{ |
| |r_{c}| \times \partial{s_c}/\partial{x} |
| -s_c \times {\partial{r_{c}}}/{\partial{x}}} |
| {\left ( r_{c} \right )^2} |
| \right ) |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \frac{\partial{s_{\textit{face}}}}{\partial{y}} &= |
| \frac{1}{2} \times |
| \left ( |
| \frac{ |
| |r_{c}| \times \partial{s_c}/\partial{y} |
| -s_c \times {\partial{r_{c}}}/{\partial{y}}} |
| {\left ( r_{c} \right )^2} |
| \right )\\ |
| \frac{\partial{t_{\textit{face}}}}{\partial{x}} &= |
| \frac{1}{2} \times |
| \left ( |
| \frac{ |
| |r_{c}| \times \partial{t_c}/\partial{x} |
| -t_c \times {\partial{r_{c}}}/{\partial{x}}} |
| {\left ( r_{c} \right )^2} |
| \right ) \\ |
| \frac{\partial{t_{\textit{face}}}}{\partial{y}} &= |
| \frac{1}{2} \times |
| \left ( |
| \frac{ |
| |r_{c}| \times \partial{t_c}/\partial{y} |
| -t_c \times {\partial{r_{c}}}/{\partial{y}}} |
| {\left ( r_{c} \right )^2} |
| \right ) |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| ifdef::editing-notes[] |
| [NOTE] |
| .editing-note |
| ==== |
| (Bill) Note that we never revisited ARB_texture_cubemap after we introduced |
| dependent texture fetches (ARB_fragment_program and ARB_fragment_shader). |
| |
| The derivatives of [eq]#s~face~# and [eq]#t~face~# are only valid for |
| non-dependent texture fetches (pre OpenGL 2.0). |
| ==== |
| endif::editing-notes[] |
| |
| |
| [[textures-lod-and-scale-factor]] |
| === Scale Factor Operation, LOD Operation and Image Level(s) Selection |
| |
| LOD selection can: be either explicit (provided explicitly by the image |
| instruction) or implicit (determined from a scale factor calculated from the |
| derivatives). |
| The LOD must: be computed with pname:mipmapPrecisionBits of accuracy. |
| |
| |
| [[textures-scale-factor]] |
| ==== Scale Factor Operation |
| |
| The magnitude of the derivatives are calculated by: |
| |
| {empty}:: [eq]#m~ux~ = {vert}{partial}s/{partial}x{vert} {times} w~base~# |
| {empty}:: [eq]#m~vx~ = {vert}{partial}t/{partial}x{vert} {times} h~base~# |
| {empty}:: [eq]#m~wx~ = {vert}{partial}r/{partial}x{vert} {times} d~base~# |
| |
| {empty}:: [eq]#m~uy~ = {vert}{partial}s/{partial}y{vert} {times} w~base~# |
| {empty}:: [eq]#m~vy~ = {vert}{partial}t/{partial}y{vert} {times} h~base~# |
| {empty}:: [eq]#m~wy~ = {vert}{partial}r/{partial}y{vert} {times} d~base~# |
| |
| |
| where: |
| |
| {empty}:: [eq]#{partial}t/{partial}x = {partial}t/{partial}y = 0# (for 1D |
| images) |
| {empty}:: [eq]#{partial}r/{partial}x = {partial}r/{partial}y = 0# (for 1D, |
| 2D or Cube images) |
| |
| and: |
| |
| {empty}:: [eq]#w~base~ = image.w# |
| {empty}:: [eq]#h~base~ = image.h# |
| {empty}:: [eq]#d~base~ = image.d# |
| |
| (for the pname:baseMipLevel, from the image descriptor). |
| |
| ifdef::VK_NV_corner_sampled_image[] |
| |
| For corner-sampled images, the [eq]#w~base~#, [eq]#h~base~#, and |
| [eq]#d~base~# are instead: |
| |
| {empty}:: [eq]#w~base~ = image.w - 1# |
| {empty}:: [eq]#h~base~ = image.h - 1# |
| {empty}:: [eq]#d~base~ = image.d - 1# |
| |
| endif::VK_NV_corner_sampled_image[] |
| |
| A point sampled in screen space has an elliptical footprint in texture |
| space. |
| The minimum and maximum scale factors [eq]#({rho}~min~, {rho}~max~)# should: |
| be the minor and major axes of this ellipse. |
| |
| The _scale factors_ [eq]#{rho}~x~# and [eq]#{rho}~y~#, calculated from the |
| magnitude of the derivatives in x and y, are used to compute the minimum and |
| maximum scale factors. |
| |
| [eq]#{rho}~x~# and [eq]#{rho}~y~# may: be approximated with functions |
| [eq]#f~x~# and [eq]#f~y~#, subject to the following constraints: |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| & f_x \text{\ is\ continuous\ and\ monotonically\ increasing\ in\ each\ of\ } |
| m_{ux}, |
| m_{vx}, \text{\ and\ } |
| m_{wx} \\ |
| & f_y \text{\ is\ continuous\ and\ monotonically\ increasing\ in\ each\ of\ } |
| m_{uy}, |
| m_{vy}, \text{\ and\ } |
| m_{wy} |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \max(|m_{ux}|, |m_{vx}|, |m_{wx}|) \leq f_{x} |
| \leq \sqrt{2} (|m_{ux}| + |m_{vx}| + |m_{wx}|) \\ |
| \max(|m_{uy}|, |m_{vy}|, |m_{wy}|) \leq f_{y} |
| \leq \sqrt{2} (|m_{uy}| + |m_{vy}| + |m_{wy}|) |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| |
| ifdef::editing-notes[] |
| [NOTE] |
| .editing-note |
| ==== |
| (Bill) For reviewers only - anticipating questions. |
| |
| We only support implicit derivatives for normalized texel coordinates. |
| |
| So we are documenting the derivatives in s,t,r (normalized texel |
| coordinates) rather than u,v,w (unnormalized texel coordinates) as in OpenGL |
| and OpenGL ES specifications. |
| (I know, u,v,w is the way it has been documented since OpenGL V1.0.) |
| |
| Also there is no reason to have conditional application of [eq]#w~base~, |
| h~base~, d~base~# for rectangle textures either, since they do not support |
| implicit derivatives. |
| ==== |
| endif::editing-notes[] |
| |
| |
| The minimum and maximum scale factors [eq]#({rho}~min~,{rho}~max~)# are |
| determined by: |
| |
| {empty}:: [eq]#{rho}~max~ = max({rho}~x~, {rho}~y~)# |
| {empty}:: [eq]#{rho}~min~ = min({rho}~x~, {rho}~y~)# |
| |
| The ratio of anisotropy is determined by: |
| |
| {empty}:: [eq]#{eta} = min({rho}~max~/{rho}~min~, max~Aniso~)# |
| |
| where: |
| |
| {empty}:: [eq]#sampler.max~Aniso~ = pname:maxAnisotropy# (from sampler |
| descriptor) |
| {empty}:: [eq]#limits.max~Aniso~ = pname:maxSamplerAnisotropy# (from |
| physical device limits) |
| {empty}:: [eq]#max~Aniso~ = min(sampler.max~Aniso~, limits.max~Aniso~)# |
| |
| If [eq]#{rho}~max~ = {rho}~min~ = 0#, then all the partial derivatives are |
| zero, the fragment's footprint in texel space is a point, and [eq]#{eta}# |
| should: be treated as 1. |
| If [eq]#{rho}~max~ {neq} 0# and [eq]#{rho}~min~ = 0# then all partial |
| derivatives along one axis are zero, the fragment's footprint in texel space |
| is a line segment, and [eq]#{eta}# should: be treated as [eq]#max~Aniso~#. |
| However, anytime the footprint is small in texel space the implementation |
| may: use a smaller value of [eq]#{eta}#, even when [eq]#{rho}~min~# is zero |
| or close to zero. |
| If either slink:VkPhysicalDeviceFeatures::pname:samplerAnisotropy or |
| slink:VkSamplerCreateInfo::pname:anisotropyEnable are ename:VK_FALSE, |
| [eq]#max~Aniso~# is set to 1. |
| |
| If [eq]#{eta} = 1#, sampling is isotropic. |
| If [eq]#{eta} > 1#, sampling is anisotropic. |
| |
| The sampling rate ([eq]#N#) is derived as: |
| |
| {empty}:: [eq]#N = {lceil}{eta}{rceil}# |
| |
| An implementation may: round [eq]#N# up to the nearest supported sampling |
| rate. |
| An implementation may: use the value of [eq]#N# as an approximation of |
| [eq]#{eta}#. |
| |
| |
| [[textures-level-of-detail-operation]] |
| ==== LOD Operation |
| |
| The LOD parameter [eq]#{lambda}# is computed as follows: |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \lambda_{base}(x,y) & = |
| \begin{cases} |
| shaderOp.Lod & \text{(from optional SPIR-V operand)} \\ |
| \log_2 \left ( \frac{\rho_{max}}{\eta} \right ) & \text{otherwise} |
| \end{cases} \\ |
| \lambda'(x,y) & = \lambda_{base} + \mathbin{clamp}(sampler.bias + shaderOp.bias,-maxSamplerLodBias,maxSamplerLodBias) \\ |
| \lambda & = |
| \begin{cases} |
| lod_{max}, & \lambda' > lod_{max} \\ |
| \lambda', & lod_{min} \leq \lambda' \leq lod_{max} \\ |
| lod_{min}, & \lambda' < lod_{min} \\ |
| \textit{undefined}, & lod_{min} > lod_{max} |
| \end{cases} |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| where: |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| sampler.bias & = mipLodBias & \text{(from sampler descriptor)} \\ |
| shaderOp.bias & = |
| \begin{cases} |
| Bias & \text{(from optional SPIR-V operand)} \\ |
| 0 & \text{otherwise} |
| \end{cases} \\ |
| sampler.lod_{min} & = minLod & \text{(from sampler descriptor)} \\ |
| shaderOp.lod_{min} & = |
| \begin{cases} |
| MinLod & \text{(from optional SPIR-V operand)} \\ |
| 0 & \text{otherwise} |
| \end{cases} \\ |
| \\ |
| lod_{min} & = \max(sampler.lod_{min}, shaderOp.lod_{min}) \\ |
| lod_{max} & = maxLod & \text{(from sampler descriptor)} |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| and [eq]#maxSamplerLodBias# is the value of the slink:VkPhysicalDeviceLimits |
| feature <<limits-maxSamplerLodBias, pname:maxSamplerLodBias>>. |
| |
| |
| [[textures-image-level-selection]] |
| ==== Image Level(s) Selection |
| |
| The image level(s) [eq]#d#, [eq]#d~hi~#, and [eq]#d~lo~# which texels are |
| read from are determined by an image-level parameter [eq]#d~l~#, which is |
| computed based on the LOD parameter, as follows: |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| d_{l} = |
| \begin{cases} |
| nearest(d'), & \text{mipmapMode is VK\_SAMPLER\_MIPMAP\_MODE\_NEAREST} \\ |
| d', & \text{otherwise} |
| \end{cases} |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| where: |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| ifdef::VK_EXT_image_view_min_lod[] |
| d' = max(level_{base} + \text{clamp}(\lambda, 0, q), minLod_{imageView}) |
| endif::VK_EXT_image_view_min_lod[] |
| ifndef::VK_EXT_image_view_min_lod[] |
| d' = level_{base} + \text{clamp}(\lambda, 0, q) |
| endif::VK_EXT_image_view_min_lod[] |
| |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| nearest(d') & = |
| \begin{cases} |
| \left \lceil d' + 0.5\right \rceil - 1, & |
| \text{preferred} \\ |
| \left \lfloor d' + 0.5\right \rfloor, & |
| \text{alternative} |
| \end{cases} |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| and: |
| |
| ifdef::VK_EXT_image_view_min_lod[] |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| minLod_{imageView} & = |
| \begin{cases} |
| minLodFloat_{imageView}, & \text{preferred} \\ |
| minLodInteger_{imageView}, & \text{alternative} |
| \end{cases} \\ |
| level_{base} & = baseMipLevel \\ |
| q & = levelCount - 1 |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| endif::VK_EXT_image_view_min_lod[] |
| ifndef::VK_EXT_image_view_min_lod[] |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| level_{base} & = baseMipLevel \\ |
| q & = levelCount - 1 |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| endif::VK_EXT_image_view_min_lod[] |
| |
| pname:baseMipLevel and pname:levelCount are taken from the |
| pname:subresourceRange of the image view. |
| |
| ifdef::VK_EXT_image_view_min_lod[] |
| [eq]#minLod~imageView~# must: be less or equal to [eq]#level~base~ + q#. |
| endif::VK_EXT_image_view_min_lod[] |
| |
| If the sampler's pname:mipmapMode is ename:VK_SAMPLER_MIPMAP_MODE_NEAREST, |
| then the level selected is [eq]#d = d~l~#. |
| |
| If the sampler's pname:mipmapMode is ename:VK_SAMPLER_MIPMAP_MODE_LINEAR, |
| two neighboring levels are selected: |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| d_{hi} & = \left\lfloor d_{l} \right\rfloor \\ |
| d_{lo} & = min( d_{hi} + 1, level_{base} + q ) \\ |
| \delta & = d_{l} - d_{hi} |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| [eq]#{delta}# is the fractional value, quantized to the number of |
| <<limits-mipmapPrecisionBits, mipmap precision bits>>, used for |
| <<textures-texel-filtering, linear filtering>> between levels. |
| |
| |
| [[textures-normalized-to-unnormalized]] |
| === (s,t,r,q,a) to (u,v,w,a) Transformation |
| |
| The normalized texel coordinates are scaled by the image level dimensions |
| and the array layer is selected. |
| |
| This transformation is performed once for each level used in |
| <<textures-texel-filtering,filtering>> (either [eq]#d#, or [eq]#d~hi~# and |
| [eq]#d~lo~#). |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| u(x,y) & = s(x,y) \times width_{scale} + \Delta_i\\ |
| v(x,y) & = |
| \begin{cases} |
| 0 & \text{for 1D images} \\ |
| t(x,y) \times height_{scale} + \Delta_j & \text{otherwise} |
| \end{cases} \\ |
| w(x,y) & = |
| \begin{cases} |
| 0 & \text{for 2D or Cube images} \\ |
| r(x,y) \times depth_{scale} + \Delta_k & \text{otherwise} |
| \end{cases} \\ |
| \\ |
| a(x,y) & = |
| \begin{cases} |
| a(x,y) & \text{for array images} \\ |
| 0 & \text{otherwise} |
| \end{cases} |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| where: |
| |
| {empty}:: [eq]#width~scale~ = width~level~# |
| {empty}:: [eq]#height~scale~ = height~level~# |
| {empty}:: [eq]#depth~scale~ = depth~level~# |
| |
| ifdef::VK_NV_corner_sampled_image[] |
| for conventional images, and: |
| |
| {empty}:: [eq]#width~scale~ = width~level~ - 1# |
| {empty}:: [eq]#height~scale~ = height~level~ - 1# |
| {empty}:: [eq]#depth~scale~ = depth~level~ - 1# |
| |
| for corner-sampled images. |
| endif::VK_NV_corner_sampled_image[] |
| |
| and where [eq]#({DeltaUpper}~i~, {DeltaUpper}~j~, {DeltaUpper}~k~)# are |
| taken from the image instruction if it includes a code:ConstOffset or |
| code:Offset operand, otherwise they are taken to be zero. |
| |
| |
| Operations then proceed to Unnormalized Texel Coordinate Operations. |
| |
| |
| == Unnormalized Texel Coordinate Operations |
| |
| |
| [[textures-unnormalized-to-integer]] |
| === (u,v,w,a) to (i,j,k,l,n) Transformation and Array Layer Selection |
| |
| The unnormalized texel coordinates are transformed to integer texel |
| coordinates relative to the selected mipmap level. |
| |
| The layer index [eq]#l# is computed as: |
| |
| {empty}:: [eq]#l = clamp(RNE(a), 0, pname:layerCount - 1) {plus} |
| pname:baseArrayLayer# |
| |
| where pname:layerCount is the number of layers in the image subresource |
| range of the image view, pname:baseArrayLayer is the first layer from the |
| subresource range, and where: |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \mathbin{RNE}(a) & = |
| \begin{cases} |
| \mathbin{roundTiesToEven}(a) & \text{preferred, from IEEE Std 754-2008 Floating-Point Arithmetic} \\ |
| \left \lfloor a + 0.5 \right \rfloor & \text{alternative} |
| \end{cases} |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| The sample index [eq]#n# is assigned the value 0. |
| |
| Nearest filtering (ename:VK_FILTER_NEAREST) computes the integer texel |
| coordinates that the unnormalized coordinates lie within: |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| i &= \left\lfloor u + shift \right\rfloor \\ |
| j &= \left\lfloor v + shift \right\rfloor \\ |
| k &= \left\lfloor w + shift \right\rfloor |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| where: |
| |
| {empty}:: [eq]#shift = 0.0# |
| |
| ifdef::VK_NV_corner_sampled_image[] |
| for conventional images, and: |
| |
| {empty}:: [eq]#shift = 0.5# |
| |
| for corner-sampled images. |
| endif::VK_NV_corner_sampled_image[] |
| |
| Linear filtering (ename:VK_FILTER_LINEAR) computes a set of neighboring |
| coordinates which bound the unnormalized coordinates. |
| The integer texel coordinates are combinations of [eq]#i~0~# or [eq]#i~1~#, |
| [eq]#j~0~# or [eq]#j~1~#, [eq]#k~0~# or [eq]#k~1~#, as well as weights |
| [eq]#{alpha}, {beta}#, and [eq]#{gamma}#. |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| i_0 &= \left\lfloor u - shift \right\rfloor \\ |
| i_1 &= i_0 + 1 \\ |
| j_0 &= \left\lfloor v - shift \right\rfloor \\ |
| j_1 &= j_0 + 1 \\ |
| k_0 &= \left\lfloor w - shift \right\rfloor \\ |
| k_1 &= k_0 + 1 |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \alpha &= \mathbin{frac}\left(u - shift\right) \\[1em] |
| \beta &= \mathbin{frac}\left(v - shift\right) \\[1em] |
| \gamma &= \mathbin{frac}\left(w - shift\right) |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| where: |
| |
| {empty}:: [eq]#shift = 0.5# |
| |
| ifdef::VK_NV_corner_sampled_image[] |
| for conventional images, and: |
| |
| {empty}:: [eq]#shift = 0.0# |
| |
| for corner-sampled images, |
| endif::VK_NV_corner_sampled_image[] |
| and where: |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \mathbin{frac}(x) = x - \left\lfloor x \right\rfloor |
| ++++++++++++++++++++++++ |
| where the number of fraction bits retained is specified by |
| sname:VkPhysicalDeviceLimits::pname:subTexelPrecisionBits. |
| |
| ifdef::VK_IMG_filter_cubic,VK_EXT_filter_cubic[] |
| Cubic filtering (ename:VK_FILTER_CUBIC_EXT) computes a set of neighboring |
| coordinates which bound the unnormalized coordinates. |
| The integer texel coordinates are combinations of [eq]#i~0~#, [eq]#i~1~#, |
| [eq]#i~2~# or [eq]#i~3~#, [eq]#j~0~#, [eq]#j~1~#, [eq]#j~2~# or [eq]#j~3~#, |
| ifndef::VK_EXT_filter_cubic[] |
| as well as weights [eq]#{alpha}# and [eq]#{beta}#. |
| endif::VK_EXT_filter_cubic[] |
| ifdef::VK_EXT_filter_cubic[] |
| [eq]#k~0~#, [eq]#k~1~#, [eq]#k~2~# or [eq]#k~3~#, as well as weights |
| [eq]#{alpha}#, [eq]#{beta}#, and [eq]#{gamma}#. |
| endif::VK_EXT_filter_cubic[] |
| |
| ifndef::VK_EXT_filter_cubic[] |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| i_{0} & = {\left \lfloor {u - \frac{3}{2}} \right \rfloor} & i_{1} & = i_{0} + 1 & i_{2} & = i_{1} + 1 & i_{3} & = i_{2} + 1 \\[1em] |
| j_{0} & = {\left \lfloor {v - \frac{3}{2}} \right \rfloor} & j_{1} & = j_{0} + 1 & j_{2} & = j_{1} + 1 & j_{3} & = j_{2} + 1 |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| alpha &= \mathbin{frac}\left(u - \frac{1}{2}\right) \\[1em] |
| \beta &= \mathbin{frac}\left(v - \frac{1}{2}\right) |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| endif::VK_EXT_filter_cubic[] |
| |
| ifdef::VK_EXT_filter_cubic[] |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| i_{0} & = {\left \lfloor {u - \frac{3}{2}} \right \rfloor} & i_{1} & = i_{0} + 1 & i_{2} & = i_{1} + 1 & i_{3} & = i_{2} + 1 \\[1em] |
| j_{0} & = {\left \lfloor {v - \frac{3}{2}} \right \rfloor} & j_{1} & = j_{0} + 1 & j_{2} & = j_{1} + 1 & j_{3} & = j_{2} + 1 \\[1em] |
| k_{0} & = {\left \lfloor {w - \frac{3}{2}} \right \rfloor} & k_{1} & = k_{0} + 1 & k_{2} & = k_{1} + 1 & k_{3} & = k_{2} + 1 |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \alpha &= \mathbin{frac}\left(u - \frac{1}{2}\right) \\[1em] |
| \beta &= \mathbin{frac}\left(v - \frac{1}{2}\right) \\[1em] |
| \gamma &= \mathbin{frac}\left(w - \frac{1}{2}\right) |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| endif::VK_EXT_filter_cubic[] |
| |
| where: |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \mathbin{frac}(x) = x - \left\lfloor x \right\rfloor |
| ++++++++++++++++++++++++ |
| |
| where the number of fraction bits retained is specified by |
| sname:VkPhysicalDeviceLimits::pname:subTexelPrecisionBits. |
| endif::VK_IMG_filter_cubic,VK_EXT_filter_cubic[] |
| |
| |
| [[textures-integer-coordinate-operations]] |
| == Integer Texel Coordinate Operations |
| |
| ifdef::VK_AMD_shader_image_load_store_lod[] |
| Integer texel coordinate operations may: supply a LOD which texels are to be |
| read from or written to using the optional SPIR-V operand code:Lod. |
| endif::VK_AMD_shader_image_load_store_lod[] |
| ifndef::VK_AMD_shader_image_load_store_lod[] |
| The code:OpImageFetch and code:OpImageFetchSparse SPIR-V instructions may: |
| supply a LOD from which texels are to be fetched using the optional SPIR-V |
| operand code:Lod. |
| Other integer-coordinate operations must: not. |
| endif::VK_AMD_shader_image_load_store_lod[] |
| If the code:Lod is provided then it must: be an integer. |
| |
| The image level selected is: |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| d & = level_{base} + |
| \begin{cases} |
| Lod & \text{(from optional SPIR-V operand)} \\ |
| 0 & \text{otherwise} |
| \end{cases} \\ |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| If [eq]#d# does not lie in the range [eq]#[pname:baseMipLevel, |
| pname:baseMipLevel {plus} pname:levelCount)# |
| ifdef::VK_EXT_image_view_min_lod[] |
| or [eq]#d# is less than minLodInteger~imageView~, |
| endif::VK_EXT_image_view_min_lod[] |
| then any values fetched are |
| ifdef::VK_EXT_robustness2[] |
| zero if the <<features-robustImageAccess2, pname:robustImageAccess2>> |
| feature is enabled, otherwise are |
| endif::VK_EXT_robustness2[] |
| undefined:, and any writes (if supported) are discarded. |
| |
| |
| [[textures-sample-operations]] |
| == Image Sample Operations |
| |
| |
| [[textures-wrapping-operation]] |
| === Wrapping Operation |
| |
| ifdef::VK_EXT_non_seamless_cube_map[] |
| If the used sampler was created without |
| ename:VK_SAMPLER_CREATE_NON_SEAMLESS_CUBE_MAP_BIT_EXT, |
| endif::VK_EXT_non_seamless_cube_map[] |
| code:Cube images ignore the wrap modes specified in the sampler. |
| Instead, if ename:VK_FILTER_NEAREST is used within a mip level then |
| ename:VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE is used, and if |
| ename:VK_FILTER_LINEAR is used within a mip level then sampling at the edges |
| is performed as described earlier in the <<textures-cubemapedge,Cube map |
| edge handling>> section. |
| |
| The first integer texel coordinate i is transformed based on the |
| pname:addressModeU parameter of the sampler. |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| i &= |
| \begin{cases} |
| i \bmod size & \text{for repeat} \\ |
| (size - 1) - \mathbin{mirror} |
| ((i \bmod (2 \times size)) - size) & \text{for mirrored repeat} \\ |
| \mathbin{clamp}(i,0,size-1) & \text{for clamp to edge} \\ |
| \mathbin{clamp}(i,-1,size) & \text{for clamp to border} \\ |
| \mathbin{clamp}(\mathbin{mirror}(i),0,size-1) & \text{for mirror clamp to edge} |
| \end{cases} |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| where: |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| & \mathbin{mirror}(n) = |
| \begin{cases} |
| n & \text{for}\ n \geq 0 \\ |
| -(1+n) & \text{otherwise} |
| \end{cases} |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| [eq]#j# (for 2D and Cube image) and [eq]#k# (for 3D image) are similarly |
| transformed based on the pname:addressModeV and pname:addressModeW |
| parameters of the sampler, respectively. |
| |
| |
| [[textures-gather]] |
| === Texel Gathering |
| |
| SPIR-V instructions with code:Gather in the name return a vector derived |
| from 4 texels in the base level of the image view. |
| The rules for the ename:VK_FILTER_LINEAR minification filter are applied to |
| identify the four selected texels. |
| Each texel is then converted to an RGBA value according to |
| <<textures-conversion-to-rgba,conversion to RGBA>> and then |
| <<textures-component-swizzle,swizzled>>. |
| A four-component vector is then assembled by taking the component indicated |
| by the code:Component value in the instruction from the swizzled color value |
| of the four texels. |
| If the operation does not use the code:ConstOffsets image operand then the |
| four texels form the 2 {times} 2 rectangle used for texture filtering: |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \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{aligned} |
| ++++++++++++++++++++++++ |
| |
| If the operation does use the code:ConstOffsets image operand then the |
| offsets allow a custom filter to be defined: |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \tau[R] &= \tau_{i0j0 + \Delta_0}[level_{base}][comp] \\ |
| \tau[G] &= \tau_{i0j0 + \Delta_1}[level_{base}][comp] \\ |
| \tau[B] &= \tau_{i0j0 + \Delta_2}[level_{base}][comp] \\ |
| \tau[A] &= \tau_{i0j0 + \Delta_3}[level_{base}][comp] |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| where: |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \tau[level_{base}][comp] &= |
| \begin{cases} |
| \tau[level_{base}][R], & \text{for}\ comp = 0 \\ |
| \tau[level_{base}][G], & \text{for}\ comp = 1 \\ |
| \tau[level_{base}][B], & \text{for}\ comp = 2 \\ |
| \tau[level_{base}][A], & \text{for}\ comp = 3 |
| \end{cases}\\ |
| comp & \,\text{from SPIR-V operand Component} |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| ifdef::VK_VERSION_1_1,VK_KHR_sampler_ycbcr_conversion[] |
| code:OpImage*Gather must: not be used on a sampled image with |
| <<samplers-YCbCr-conversion,sampler {YCbCr} conversion>> enabled. |
| endif::VK_VERSION_1_1,VK_KHR_sampler_ycbcr_conversion[] |
| |
| ifdef::VK_EXT_image_view_min_lod[] |
| If [eq]#level~base~ < minLodInteger~imageView~#, then any values fetched are |
| ifdef::VK_EXT_robustness2[] |
| zero if <<features-robustImageAccess2, pname:robustImageAccess2>> is |
| enabled. |
| Otherwise values are |
| endif::VK_EXT_robustness2[] |
| undefined:. |
| endif::VK_EXT_image_view_min_lod[] |
| |
| |
| [[textures-texel-filtering]] |
| === Texel Filtering |
| |
| Texel filtering is first performed for each level (either [eq]#d# or |
| [eq]#d~hi~# and [eq]#d~lo~#). |
| |
| If [eq]#{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 |
| pname:magFilter in the sampler. |
| If [eq]#{lambda}# is greater than zero, the texture is said to be |
| _minified_, and the filter mode within a mip level is selected by the |
| pname:minFilter in the sampler. |
| |
| |
| [[textures-texel-nearest-filtering]] |
| ==== Texel Nearest Filtering |
| |
| Within a mip level, ename:VK_FILTER_NEAREST filtering selects a single value |
| using the [eq]#(i, j, k)# texel coordinates, with all texels taken from |
| layer l. |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \tau[level] &= |
| \begin{cases} |
| \tau_{ijk}[level], & \text{for 3D image} \\ |
| \tau_{ij}[level], & \text{for 2D or Cube image} \\ |
| \tau_{i}[level], & \text{for 1D image} |
| \end{cases} |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| |
| [[textures-texel-linear-filtering]] |
| ==== Texel Linear Filtering |
| |
| Within a mip level, ename:VK_FILTER_LINEAR filtering combines 8 (for 3D), 4 |
| (for 2D or Cube), or 2 (for 1D) texel values, together with their linear |
| weights. |
| The linear weights are derived from the fractions computed earlier: |
| |
| [latexmath] |
| |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| w_{i_0} &= (1-\alpha) \\ |
| w_{i_1} &= (\alpha) \\ |
| w_{j_0} &= (1-\beta) \\ |
| w_{j_1} &= (\beta) \\ |
| w_{k_0} &= (1-\gamma) \\ |
| w_{k_1} &= (\gamma) |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| ifndef::VK_VERSION_1_2,VK_EXT_sampler_filter_minmax[] |
| The values of multiple texels, together with their weights, are combined |
| using a weighted average to produce a filtered value: |
| endif::VK_VERSION_1_2,VK_EXT_sampler_filter_minmax[] |
| |
| ifdef::VK_VERSION_1_2,VK_EXT_sampler_filter_minmax[] |
| The values of multiple texels, together with their weights, are combined to |
| produce a filtered value. |
| |
| The slink:VkSamplerReductionModeCreateInfo::pname:reductionMode can: control |
| the process by which multiple texels, together with their weights, are |
| combined to produce a filtered texture value. |
| |
| When the pname:reductionMode is set (explicitly or implicitly) to |
| ename:VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE, a weighted average is |
| computed: |
| endif::VK_VERSION_1_2,VK_EXT_sampler_filter_minmax[] |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \tau_{3D} &= \sum_{k=k_0}^{k_1}\sum_{j=j_0}^{j_1}\sum_{i=i_0}^{i_1}(w_{i})(w_{j})(w_{k})\tau_{ijk} \\ |
| \tau_{2D} &= \sum_{j=j_0}^{j_1}\sum_{i=i_0}^{i_1}(w_{i})(w_{j})\tau_{ij} \\ |
| \tau_{1D} &= \sum_{i=i_0}^{i_1}(w_{i})\tau_{i} |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| ifdef::VK_VERSION_1_2,VK_EXT_sampler_filter_minmax[] |
| However, if the reduction mode is ename:VK_SAMPLER_REDUCTION_MODE_MIN or |
| ename:VK_SAMPLER_REDUCTION_MODE_MAX, the process operates on the above set |
| of multiple texels, together with their weights, computing a component-wise |
| minimum or maximum, respectively, of the components of the set of texels |
| with non-zero weights. |
| endif::VK_VERSION_1_2,VK_EXT_sampler_filter_minmax[] |
| |
| |
| ifdef::VK_IMG_filter_cubic,VK_EXT_filter_cubic[] |
| [[textures-texel-cubic-filtering]] |
| ==== Texel Cubic Filtering |
| |
| Within a mip level, ename:VK_FILTER_CUBIC_EXT, filtering computes a weighted |
| average of |
| ifdef::VK_EXT_filter_cubic[] |
| 64 (for 3D), |
| endif::VK_EXT_filter_cubic[] |
| 16 (for 2D), or 4 (for 1D) texel values, together with their |
| ifndef::VK_QCOM_filter_cubic_weights[] |
| Catmull-Rom weights. |
| endif::VK_QCOM_filter_cubic_weights[] |
| ifdef::VK_QCOM_filter_cubic_weights[] |
| Catmull-Rom, Zero Tangent Cardinal, B-Spline, or Mitchell-Netravali weights |
| as specified by slink:VkSamplerCubicWeightsCreateInfoQCOM. |
| endif::VK_QCOM_filter_cubic_weights[] |
| |
| |
| Catmull-Rom weights |
| ifdef::VK_QCOM_filter_cubic_weights[] |
| specified by ename:VK_CUBIC_FILTER_WEIGHTS_CATMULL_ROM_QCOM |
| endif::VK_QCOM_filter_cubic_weights[] |
| are derived from the fractions computed earlier. |
| |
| ifndef::VK_EXT_filter_cubic[] |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \begin{bmatrix} |
| w_{i_0}\phantom{,} w_{i_1}\phantom{,} w_{i_2}\phantom{,} w_{i_3} |
| \end{bmatrix} |
| = \frac{1}{2} |
| \begin{bmatrix} |
| 1 & \alpha & \alpha^2 & \alpha^3 |
| \end{bmatrix} |
| \begin{bmatrix} |
| \phantom{-}0 & \phantom{-}2 & \phantom{-}0 & \phantom{-}0 \\ |
| -1 & \phantom{-}0 & \phantom{-}1 & \phantom{-}0 \\ |
| \phantom{-}2 & -5 & \phantom{-}4 & -1 \\ |
| -1 & \phantom{-}3 & -3 & \phantom{-}1 |
| \end{bmatrix} |
| \\ |
| \begin{bmatrix} |
| w_{j_0}\phantom{,} w_{j_1}\phantom{,} w_{j_2}\phantom{,} w_{j_3} |
| \end{bmatrix} |
| = \frac{1}{2} |
| \begin{bmatrix} |
| 1 & \beta & \beta^2 & \beta^3 |
| \end{bmatrix} |
| \begin{bmatrix} |
| \phantom{-}0 & \phantom{-}2 & \phantom{-}0 & \phantom{-}0 \\ |
| -1 & \phantom{-}0 & \phantom{-}1 & \phantom{-}0 \\ |
| \phantom{-}2 & -5 & \phantom{-}4 & -1 \\ |
| -1 & \phantom{-}3 & -3 & \phantom{-}1 |
| \end{bmatrix} |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| The values of multiple texels, together with their weights, are combined |
| using a weighted average to produce a filtered value: |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \tau_{2D} &= \sum_{j=j_0}^{j_3}\sum_{i=i_0}^{i_3}(w_{i})(w_{j})\tau_{ij} \\ |
| \tau_{1D} &= \sum_{i=i_0}^{i_3}(w_{i})\tau_{i} |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| endif::VK_EXT_filter_cubic[] |
| |
| ifdef::VK_EXT_filter_cubic[] |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \begin{bmatrix} |
| w_{i_0}\phantom{,} w_{i_1}\phantom{,} w_{i_2}\phantom{,} w_{i_3} |
| \end{bmatrix} |
| = \frac{1}{2} |
| \begin{bmatrix} |
| 1 & \alpha & \alpha^2 & \alpha^3 |
| \end{bmatrix} |
| \begin{bmatrix} |
| \phantom{-}0 & \phantom{-}2 & \phantom{-}0 & \phantom{-}0 \\ |
| -1 & \phantom{-}0 & \phantom{-}1 & \phantom{-}0 \\ |
| \phantom{-}2 & -5 & \phantom{-}4 & -1 \\ |
| -1 & \phantom{-}3 & -3 & \phantom{-}1 |
| \end{bmatrix} |
| \\ |
| \begin{bmatrix} |
| w_{j_0}\phantom{,} w_{j_1}\phantom{,} w_{j_2}\phantom{,} w_{j_3} |
| \end{bmatrix} |
| = \frac{1}{2} |
| \begin{bmatrix} |
| 1 & \beta & \beta^2 & \beta^3 |
| \end{bmatrix} |
| \begin{bmatrix} |
| \phantom{-}0 & \phantom{-}2 & \phantom{-}0 & \phantom{-}0 \\ |
| -1 & \phantom{-}0 & \phantom{-}1 & \phantom{-}0 \\ |
| \phantom{-}2 & -5 & \phantom{-}4 & -1 \\ |
| -1 & \phantom{-}3 & -3 & \phantom{-}1 |
| \end{bmatrix} |
| \\ |
| \begin{bmatrix} |
| w_{k_0}\phantom{,} w_{k_1}\phantom{,} w_{k_2}\phantom{,} w_{k_3} |
| \end{bmatrix} |
| = \frac{1}{2} |
| \begin{bmatrix} |
| 1 & \gamma & \gamma^2 & \gamma^3 |
| \end{bmatrix} |
| \begin{bmatrix} |
| \phantom{-}0 & \phantom{-}2 & \phantom{-}0 & \phantom{-}0 \\ |
| -1 & \phantom{-}0 & \phantom{-}1 & \phantom{-}0 \\ |
| \phantom{-}2 & -5 & \phantom{-}4 & -1 \\ |
| -1 & \phantom{-}3 & -3 & \phantom{-}1 |
| \end{bmatrix} |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| ifdef::VK_QCOM_filter_cubic_weights[] |
| Zero Tangent Cardinal weights specified by |
| ename:VK_CUBIC_FILTER_WEIGHTS_ZERO_TANGENT_CARDINAL_QCOM are derived from |
| the fractions computed earlier. |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \begin{bmatrix} |
| w_{i_0}\phantom{,} w_{i_1}\phantom{,} w_{i_2}\phantom{,} w_{i_3} |
| \end{bmatrix} |
| = \frac{1}{2} |
| \begin{bmatrix} |
| 1 & \alpha & \alpha^2 & \alpha^3 |
| \end{bmatrix} |
| \begin{bmatrix} |
| \phantom{-}0 & \phantom{-}2 & \phantom{-}0 & \phantom{-}0 \\ |
| -2 & \phantom{-}0 & \phantom{-}2 & \phantom{-}0 \\ |
| \phantom{-}4 & -4 & \phantom{-}2 & -2 \\ |
| -2 & \phantom{-}2 & -2 & \phantom{-}1 |
| \end{bmatrix} |
| \\ |
| \begin{bmatrix} |
| w_{j_0}\phantom{,} w_{j_1}\phantom{,} w_{j_2}\phantom{,} w_{j_3} |
| \end{bmatrix} |
| = \frac{1}{2} |
| \begin{bmatrix} |
| 1 & \beta & \beta^2 & \beta^3 |
| \end{bmatrix} |
| \begin{bmatrix} |
| \phantom{-}0 & \phantom{-}2 & \phantom{-}0 & \phantom{-}0 \\ |
| -2 & \phantom{-}0 & \phantom{-}2 & \phantom{-}0 \\ |
| \phantom{-}4 & -4 & \phantom{-}2 & -2 \\ |
| -2 & \phantom{-}2 & -2 & \phantom{-}1 |
| \end{bmatrix} |
| \\ |
| \begin{bmatrix} |
| w_{k_0}\phantom{,} w_{k_1}\phantom{,} w_{k_2}\phantom{,} w_{k_3} |
| \end{bmatrix} |
| = \frac{1}{2} |
| \begin{bmatrix} |
| 1 & \gamma & \gamma^2 & \gamma^3 |
| \end{bmatrix} |
| \begin{bmatrix} |
| \phantom{-}0 & \phantom{-}2 & \phantom{-}0 & \phantom{-}0 \\ |
| -2 & \phantom{-}0 & \phantom{-}2 & \phantom{-}0 \\ |
| \phantom{-}4 & -4 & \phantom{-}2 & -2 \\ |
| -2 & \phantom{-}2 & -2 & \phantom{-}1 |
| \end{bmatrix} |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| B-Spline weights specified by ename:VK_CUBIC_FILTER_WEIGHTS_B_SPLINE_QCOM |
| are derived from the fractions computed earlier. |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \begin{bmatrix} |
| w_{i_0}\phantom{,} w_{i_1}\phantom{,} w_{i_2}\phantom{,} w_{i_3} |
| \end{bmatrix} |
| = \frac{1}{6} |
| \begin{bmatrix} |
| 1 & \alpha & \alpha^2 & \alpha^3 |
| \end{bmatrix} |
| \begin{bmatrix} |
| \phantom{-}1 & \phantom{-}4 & \phantom{-}1 & \phantom{-}0 \\ |
| -3 & \phantom{-}0 & \phantom{-}3 & \phantom{-}0 \\ |
| \phantom{-}3 & -6 & \phantom{-}3 & \phantom{-}0 \\ |
| -1 & \phantom{-}3 & -3 & \phantom{-}1 |
| \end{bmatrix} |
| \\ |
| \begin{bmatrix} |
| w_{j_0}\phantom{,} w_{j_1}\phantom{,} w_{j_2}\phantom{,} w_{j_3} |
| \end{bmatrix} |
| = \frac{1}{6} |
| \begin{bmatrix} |
| 1 & \beta & \beta^2 & \beta^3 |
| \end{bmatrix} |
| \begin{bmatrix} |
| \phantom{-}1 & \phantom{-}4 & \phantom{-}1 & \phantom{-}0 \\ |
| -3 & \phantom{-}0 & \phantom{-}3 & \phantom{-}0 \\ |
| \phantom{-}3 & -6 & \phantom{-}3 & \phantom{-}0 \\ |
| -1 & \phantom{-}3 & -3 & \phantom{-}1 |
| \end{bmatrix} |
| \\ |
| \begin{bmatrix} |
| w_{k_0}\phantom{,} w_{k_1}\phantom{,} w_{k_2}\phantom{,} w_{k_3} |
| \end{bmatrix} |
| = \frac{1}{6} |
| \begin{bmatrix} |
| 1 & \gamma & \gamma^2 & \gamma^3 |
| \end{bmatrix} |
| \begin{bmatrix} |
| \phantom{-}1 & \phantom{-}4 & \phantom{-}1 & \phantom{-}0 \\ |
| -3 & \phantom{-}0 & \phantom{-}3 & \phantom{-}0 \\ |
| \phantom{-}3 & -6 & \phantom{-}3 & \phantom{-}0 \\ |
| -1 & \phantom{-}3 & -3 & \phantom{-}1 |
| \end{bmatrix} |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| Mitchell-Netravali weights specified by |
| ename:VK_CUBIC_FILTER_WEIGHTS_MITCHELL_NETRAVALI_QCOM are derived from the |
| fractions computed earlier. |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \begin{bmatrix} |
| w_{i_0}\phantom{,} w_{i_1}\phantom{,} w_{i_2}\phantom{,} w_{i_3} |
| \end{bmatrix} |
| = \frac{1}{18} |
| \begin{bmatrix} |
| 1 & \alpha & \alpha^2 & \alpha^3 |
| \end{bmatrix} |
| \begin{bmatrix} |
| \phantom{-}1 & \phantom{-}16 & \phantom{-}1 & \phantom{-}0 \\ |
| -9 & \phantom{-}0 & \phantom{-}9 & \phantom{-}0 \\ |
| \phantom{-}15 & -36 & \phantom{-}27 & -6 \\ |
| -7 & \phantom{-}21 & -21 & \phantom{-}7 |
| \end{bmatrix} |
| \\ |
| \begin{bmatrix} |
| w_{j_0}\phantom{,} w_{j_1}\phantom{,} w_{j_2}\phantom{,} w_{j_3} |
| \end{bmatrix} |
| = \frac{1}{18} |
| \begin{bmatrix} |
| 1 & \beta & \beta^2 & \beta^3 |
| \end{bmatrix} |
| \begin{bmatrix} |
| \phantom{-}1 & \phantom{-}16 & \phantom{-}1 & \phantom{-}0 \\ |
| -9 & \phantom{-}0 & \phantom{-}9 & \phantom{-}0 \\ |
| \phantom{-}15 & -36 & \phantom{-}27 & -6 \\ |
| -7 & \phantom{-}21 & -21 & \phantom{-}7 |
| \end{bmatrix} |
| \\ |
| \begin{bmatrix} |
| w_{k_0}\phantom{,} w_{k_1}\phantom{,} w_{k_2}\phantom{,} w_{k_3} |
| \end{bmatrix} |
| = \frac{1}{18} |
| \begin{bmatrix} |
| 1 & \gamma & \gamma^2 & \gamma^3 |
| \end{bmatrix} |
| \begin{bmatrix} |
| \phantom{-}1 & \phantom{-}16 & \phantom{-}1 & \phantom{-}0 \\ |
| -9 & \phantom{-}0 & \phantom{-}9 & \phantom{-}0 \\ |
| \phantom{-}15 & -36 & \phantom{-}27 & -6 \\ |
| -7 & \phantom{-}21 & -21 & \phantom{-}7 |
| \end{bmatrix} |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| endif::VK_QCOM_filter_cubic_weights[] |
| |
| |
| The values of multiple texels, together with their weights, are combined to |
| produce a filtered value. |
| |
| The slink:VkSamplerReductionModeCreateInfo::pname:reductionMode can: control |
| the process by which multiple texels, together with their weights, are |
| combined to produce a filtered texture value. |
| |
| When the pname:reductionMode is set (explicitly or implicitly) to |
| ename:VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE |
| ifdef::VK_QCOM_filter_cubic_clamp[] |
| or ename:VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_RANGECLAMP_QCOM |
| endif::VK_QCOM_filter_cubic_clamp[] |
| , a weighted average is computed: |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \tau_{3D} &= \sum_{k=j_0}^{k_3}\sum_{j=j_0}^{j_3}\sum_{i=i_0}^{i_3}(w_{i})(w_{j})(w_{k})\tau_{ijk} \\ |
| \tau_{2D} &= \sum_{j=j_0}^{j_3}\sum_{i=i_0}^{i_3}(w_{i})(w_{j})\tau_{ij} \\ |
| \tau_{1D} &= \sum_{i=i_0}^{i_3}(w_{i})\tau_{i} |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| ifdef::VK_VERSION_1_2,VK_EXT_sampler_filter_minmax[] |
| However, if the reduction mode is ename:VK_SAMPLER_REDUCTION_MODE_MIN or |
| ename:VK_SAMPLER_REDUCTION_MODE_MAX, the process operates on the above set |
| of multiple texels, together with their weights, computing a component-wise |
| minimum or maximum, respectively, of the components of the set of texels |
| with non-zero weights. |
| endif::VK_VERSION_1_2,VK_EXT_sampler_filter_minmax[] |
| |
| |
| ifdef::VK_QCOM_filter_cubic_clamp[] |
| [[textures-texel-range-clamp]] |
| ==== Texel Range Clamp |
| When the pname:reductionMode is set to |
| ename:VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_RANGECLAMP_QCOM, the |
| weighted average is clamped to be within the component-wise minimum and |
| maximum of the set of texels with non-zero weights. |
| endif::VK_QCOM_filter_cubic_clamp[] |
| |
| endif::VK_EXT_filter_cubic[] |
| endif::VK_IMG_filter_cubic,VK_EXT_filter_cubic[] |
| |
| |
| [[textures-texel-mipmap-filtering]] |
| ==== Texel Mipmap Filtering |
| |
| ename:VK_SAMPLER_MIPMAP_MODE_NEAREST filtering returns the value of a single |
| mipmap level, |
| |
| [eq]#{tau} = {tau}[d]#. |
| |
| ename:VK_SAMPLER_MIPMAP_MODE_LINEAR filtering combines the values of |
| multiple mipmap levels ({tau}[hi] and {tau}[lo]), together with their linear |
| weights. |
| |
| The linear weights are derived from the fraction computed earlier: |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| w_{hi} &= (1-\delta) \\ |
| w_{lo} &= (\delta) \\ |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| ifndef::VK_VERSION_1_2,VK_EXT_sampler_filter_minmax[] |
| The values of multiple mipmap levels together with their linear weights, are |
| combined using a weighted average to produce a final filtered value: |
| endif::VK_VERSION_1_2,VK_EXT_sampler_filter_minmax[] |
| ifdef::VK_VERSION_1_2,VK_EXT_sampler_filter_minmax[] |
| The values of multiple mipmap levels, together with their weights, are |
| combined to produce a final filtered value. |
| |
| The slink:VkSamplerReductionModeCreateInfo::pname:reductionMode can: control |
| the process by which multiple texels, together with their weights, are |
| combined to produce a filtered texture value. |
| |
| When the pname:reductionMode is set (explicitly or implicitly) to |
| ename:VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE, a weighted average is |
| computed: |
| endif::VK_VERSION_1_2,VK_EXT_sampler_filter_minmax[] |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \tau &= (w_{hi})\tau[hi]+(w_{lo})\tau[lo] |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| ifdef::VK_VERSION_1_2,VK_EXT_sampler_filter_minmax[] |
| However, if the reduction mode is ename:VK_SAMPLER_REDUCTION_MODE_MIN or |
| ename:VK_SAMPLER_REDUCTION_MODE_MAX, the process operates on the above |
| values, together with their weights, computing a component-wise minimum or |
| maximum, respectively, of the components of the values with non-zero |
| weights. |
| endif::VK_VERSION_1_2,VK_EXT_sampler_filter_minmax[] |
| |
| |
| [[textures-texel-anisotropic-filtering]] |
| ==== Texel Anisotropic Filtering |
| |
| Anisotropic filtering is enabled by the pname: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 pname:magFilter, pname:minFilter and |
| pname:mipmapMode of the sampler to control the specifics of the anisotropic |
| filtering scheme used. |
| In addition, implementations should: consider pname:minLod and pname:maxLod |
| of the sampler. |
| |
| [NOTE] |
| .Note |
| ==== |
| For historical reasons, vendor implementations of anisotropic filtering |
| interpret these sampler parameters in different ways, particularly in corner |
| cases such as pname:magFilter, pname:minFilter of ename:NEAREST or |
| pname:maxAnisotropy equal to 1.0. |
| Applications should not expect consistent behavior in such cases, and should |
| use anisotropic filtering only with parameters which are expected to give a |
| quality improvement relative to etext:LINEAR filtering. |
| |
| The following describes one particular approach to implementing anisotropic |
| filtering for the 2D Image case; implementations may: choose other methods: |
| |
| Given a pname:magFilter, pname:minFilter of ename:VK_FILTER_LINEAR and a |
| pname:mipmapMode of ename:VK_SAMPLER_MIPMAP_MODE_NEAREST: |
| |
| Instead of a single isotropic sample, N isotropic samples are sampled within |
| the image footprint of the image level [eq]#d# to approximate an anisotropic |
| filter. |
| The sum [eq]#{tau}~2Daniso~# is defined using the single isotropic |
| [eq]#{tau}~2D~(u,v)# at level [eq]#d#. |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \tau_{2Daniso} & = |
| \frac{1}{N}\sum_{i=1}^{N} |
| {\tau_{2D}\left ( |
| u \left ( x - \frac{1}{2} + \frac{i}{N+1} , y \right ), |
| v \left (x-\frac{1}{2}+\frac{i}{N+1}, y \right ) |
| \right )}, |
| & \text{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 ), |
| v \left (x,y-\frac{1}{2}+\frac{i}{N+1} \right ) |
| \right )}, |
| & \text{when}\ \rho_{y} \geq \rho_{x} |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| ifdef::VK_VERSION_1_2,VK_EXT_sampler_filter_minmax[] |
| When slink:VkSamplerReductionModeCreateInfo::pname:reductionMode is set to |
| ename:VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE, the above summation is |
| used. |
| However, if the reduction mode is ename:VK_SAMPLER_REDUCTION_MODE_MIN or |
| ename:VK_SAMPLER_REDUCTION_MODE_MAX, the process operates on the above |
| values, together with their weights, computing a component-wise minimum or |
| maximum, respectively, of the components of the values with non-zero |
| weights. |
| endif::VK_VERSION_1_2,VK_EXT_sampler_filter_minmax[] |
| ==== |
| |
| |
| ifdef::VK_NV_shader_image_footprint[] |
| [[textures-footprint]] |
| == Texel Footprint Evaluation |
| |
| The SPIR-V instruction code:OpImageSampleFootprintNV evaluates the set of |
| texels from a single mip level that would be accessed during a |
| <<textures-texel-filtering, texel filtering>> operation. |
| In addition to the inputs that would be accepted by an equivalent |
| code:OpImageSample* instruction, code:OpImageSampleFootprintNV accepts two |
| additional inputs. |
| The code:Granularity input is an integer identifying the size of texel |
| groups used to evaluate the footprint. |
| Each bit in the returned footprint mask corresponds to an aligned block of |
| texels whose size is given by the following table: |
| |
| .Texel footprint granularity values |
| [width="50%",options="header"] |
| |==== |
| | code:Granularity | code:Dim = 2D | code:Dim = 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 |
| |==== |
| |
| The code:Coarse input is used to select between the two mip levels that may: |
| be accessed during texel filtering when using a pname:mipmapMode of |
| ename:VK_SAMPLER_MIPMAP_MODE_LINEAR. |
| When filtering between two mip levels, a code:Coarse value of code:true |
| requests the footprint in the lower-resolution mip level (higher level |
| number), while code:false requests the footprint in the higher-resolution |
| mip level. |
| If texel filtering would access only a single mip level, the footprint in |
| that level would be returned when code:Coarse is set to code:false; an empty |
| footprint would be returned when code:Coarse is set to code:true. |
| |
| The footprint for code:OpImageSampleFootprintNV is returned in a structure |
| with six members: |
| |
| * The first member is a boolean value that is true if the texel filtering |
| operation would access only a single mip level. |
| * The second member is a two- or three-component integer vector holding |
| the footprint anchor location. |
| For two-dimensional images, the returned components are in units of |
| eight texel groups. |
| For three-dimensional images, the returned components are in units of |
| four texel groups. |
| * The third member is a two- or three-component integer vector holding a |
| footprint offset relative to the anchor. |
| All returned components are in units of texel groups. |
| * The fourth member is a two-component integer vector mask, which holds a |
| bitfield identifying the set of texel groups in an 8x8 or 4x4x4 |
| neighborhood relative to the anchor and offset. |
| * The fifth member is an integer identifying the mip level containing the |
| footprint identified by the anchor, offset, and mask. |
| * The sixth member is an integer identifying the granularity of the |
| returned footprint. |
| |
| For footprints in two-dimensional images (code:Dim2D), the mask returned by |
| code:OpImageSampleFootprintNV indicates whether each texel group in a 8x8 |
| local neighborhood of texel groups would have one or more texels accessed |
| during texel filtering. |
| In the mask, the texel group with local group coordinates |
| latexmath:[(lgx,lgy)] is considered covered if and only if |
| |
| [latexmath] |
| +++++++++++++++++++ |
| \begin{aligned} |
| 0 \neq ((mask.x + (mask.y << 32)) \text{ \& } (1 << (lgy \times 8 + lgx))) |
| \end{aligned} |
| +++++++++++++++++++ |
| |
| where: |
| |
| * latexmath:[0 \leq lgx < 8] and latexmath:[0 \leq lgy < 8]; and |
| * latexmath:[mask] is the returned two-component mask. |
| |
| The local group with coordinates latexmath:[(lgx,lgy)] in the mask is |
| considered covered if and only if the texel filtering operation would access |
| one or more texels latexmath:[\tau_{ij}] in the returned mip level where: |
| [latexmath] |
| +++++++++++++++++++ |
| \begin{aligned} |
| i0 & = |
| \begin{cases} |
| gran.x \times (8 \times anchor.x + lgx), & \text{if } lgx + offset.x < 8 \\ |
| gran.x \times (8 \times (anchor.x - 1) + lgx), & \text{otherwise} |
| \end{cases} \\ |
| i1 & = i0 + gran.x - 1 \\ |
| j0 & = |
| \begin{cases} |
| gran.y \times (8 \times anchor.y + lgy), & \text{if } lgy + offset.y < 8 \\ |
| gran.y \times (8 \times (anchor.y - 1) + lgy), & otherwise |
| \end{cases} \\ |
| j1 & = j0 + gran.y - 1 |
| \end{aligned} |
| +++++++++++++++++++ |
| and |
| |
| * latexmath:[i0 \leq i \leq i1] and latexmath:[j0 \leq j \leq j1]; |
| * latexmath:[gran] is a two-component vector holding the width and height |
| of the texel group identified by the granularity; |
| * latexmath:[anchor] is the returned two-component anchor vector; and |
| * latexmath:[offset] is the returned two-component offset vector. |
| |
| For footprints in three-dimensional images (code:Dim3D), the mask returned |
| by code:OpImageSampleFootprintNV indicates whether each texel group in a |
| 4x4x4 local neighborhood of texel groups would have one or more texels |
| accessed during texel filtering. |
| In the mask, the texel group with local group coordinates |
| latexmath:[(lgx,lgy,lgz)], is considered covered if and only if: |
| [latexmath] |
| +++++++++++++++++++ |
| \begin{aligned} |
| 0 \neq ((mask.x + (mask.y << 32)) \text{ \& } (1 << (lgz \times 16 + lgy \times 4 + lgx))) |
| \end{aligned} |
| +++++++++++++++++++ |
| where: |
| |
| * latexmath:[0 \leq lgx < 4], latexmath:[0 \leq lgy < 4], and latexmath:[0 |
| \leq lgz < 4]; and |
| * latexmath:[mask] is the returned two-component mask. |
| |
| The local group with coordinates latexmath:[(lgx,lgy,lgz)] in the mask is |
| considered covered if and only if the texel filtering operation would access |
| one or more texels latexmath:[\tau_{ijk}] in the returned mip level where: |
| [latexmath] |
| +++++++++++++++++++ |
| \begin{aligned} |
| i0 & = |
| \begin{cases} |
| gran.x \times (4 \times anchor.x + lgx), & \text{if } lgx + offset.x < 4 \\ |
| gran.x \times (4 \times (anchor.x - 1) + lgx), & \text{otherwise} |
| \end{cases} \\ |
| i1 & = i0 + gran.x - 1 \\ |
| j0 & = |
| \begin{cases} |
| gran.y \times (4 \times anchor.y + lgy), & \text{if } lgy + offset.y < 4 \\ |
| gran.y \times (4 \times (anchor.y - 1) + lgy), & otherwise |
| \end{cases} \\ |
| j1 & = j0 + gran.y - 1 \\ |
| k0 & = |
| \begin{cases} |
| gran.z \times (4 \times anchor.z + lgz), & \text{if } lgz + offset.z < 4 \\ |
| gran.z \times (4 \times (anchor.z - 1) + lgz), & otherwise |
| \end{cases} \\ |
| k1 & = k0 + gran.z - 1 |
| \end{aligned} |
| +++++++++++++++++++ |
| and |
| |
| * latexmath:[i0 \leq i \leq i1], latexmath:[j0 \leq j \leq j1], |
| latexmath:[k0 \leq k \leq k1]; |
| * latexmath:[gran] is a three-component vector holding the width, height, |
| and depth of the texel group identified by the granularity; |
| * latexmath:[anchor] is the returned three-component anchor vector; and |
| * latexmath:[offset] is the returned three-component offset vector. |
| |
| If the sampler used by code:OpImageSampleFootprintNV enables anisotropic |
| texel filtering via pname:anisotropyEnable, it is possible that the set of |
| texel groups accessed in a mip level may be too large to be expressed using |
| an 8x8 or 4x4x4 mask using the granularity requested in the instruction. |
| In this case, the implementation uses a texel group larger than the |
| requested granularity. |
| When a larger texel group size is used, code:OpImageSampleFootprintNV |
| returns an integer granularity value that can: be interpreted in the same |
| manner as the granularity value provided to the instruction to determine the |
| texel group size used. |
| If anisotropic texel filtering is disabled in the sampler, or if an |
| anisotropic footprint can be represented as an 8x8 or 4x4x4 mask with the |
| requested granularity, code:OpImageSampleFootprintNV will use the requested |
| granularity as-is and return a granularity value of zero. |
| |
| code:OpImageSampleFootprintNV supports only two- and three-dimensional image |
| accesses (code:Dim2D and code:Dim3D), and the footprint returned is |
| undefined: if a sampler uses an addressing mode other than |
| ename:VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE. |
| |
| endif::VK_NV_shader_image_footprint[] |
| |
| |
| ifdef::VK_QCOM_image_processing[] |
| [[textures-weightimage]] |
| == Weight Image Sampling |
| |
| The SPIR-V instruction code:OpImageWeightedSampleQCOM specifies a texture |
| sampling operation involving two images: the _sampled image_ and the _weight |
| image_. |
| It is similar to bilinear filtering except more than 2x2 texels may |
| participate in the filter and the filter weights are user-specified rather |
| than computed by fixed-function hardware. |
| The weight image view defines a 2D kernel weights used during sampling. |
| |
| The code:OpImageWeightedSampleQCOM support normalized or unnormalized texel |
| coordinates. |
| In addition to the inputs that would be accepted by an equivalent |
| code:OpImageSample* instruction, code:OpImageWeightedSampleQCOM accepts a |
| code:weight input that specifies the view of a sample weight image |
| |
| The input code:weight must: be a view of a 2D or 1D image with |
| code:miplevels equal to `1`, code:samples equal to |
| ename:VK_SAMPLE_COUNT_1_BIT, created with an identity swizzle, and created |
| with code:usage that includes ename:VK_IMAGE_USAGE_SAMPLE_WEIGHT_BIT_QCOM. |
| The slink:VkImageViewSampleWeightCreateInfoQCOM specifies additional |
| parameters of the view: pname:filterCenter, pname:filterSize, and |
| pname:numPhases. |
| described in more detail below. |
| |
| The code:weight input must: be bound using a |
| <<descriptorsets-weightimage,sample weight image>> descriptor type. |
| The code:weight view defines a filtering kernel that is a region of view's |
| subresource range. |
| The kernel spans a region from integer texel coordinate [eq]#(0,0)# to |
| [eq]#(pname:filterSize.x-1, pname:filterSize.y-1)#. |
| It is valid for the view's subresource to have dimensions larger than the |
| kernel but the texels with integer coordinates greater than |
| [eq]#(pname:filterSize.width-1, pname:filterSize.height-1)# are ignored by |
| weight sampling. |
| The value returned by queries code:OpImageQuerySize, |
| code:OpImageQuerySizeLod, code:OpImageQueryLevels, and |
| code:OpImageQuerySamples return for a weight image is undefined:. |
| |
| pname:filterCenter designates an integer texel coordinate within the filter |
| kernel as being the 'center' of the kernel. |
| The center must: be in the range [eq]#(0,0)# to [eq]#(pname:filterSize.x-1, |
| pname:filterSize.y-1)#. |
| pname:numPhases describes the number of filter phases used to provide |
| sub-pixel filtering. |
| Both are described in more detail below. |
| |
| |
| [[textures-weightimage-layout]] |
| === Weight Image Layout |
| |
| The weight image specifies filtering kernel weight values. |
| A 2D image view can be used to specify a 2D matrix of filter weights. |
| For separable filers, a 1D image view can be used to specity the horizontal |
| and vertical weights. |
| |
| |
| ==== 2D Non-Separable Weight Filters |
| |
| A 2D image view defined with slink:VkImageViewSampleWeightCreateInfoQCOM |
| describes a 2D matrix [eq]#(pname:filterSize.width {times} |
| pname:filterSize.height)# of weight elements with filter's center point at |
| pname:filterCenter. |
| Note that pname:filterSize can be smaller than the view's subresource, but |
| the filter will always be located starting at integer texel coordinate |
| [eq]#(0,0)#. |
| |
| The following figure illustrates a 2D convolution filter having |
| pname:filterSize of [eq]#(4,3)# and pname:filterCenter at [eq]#(1, 1)#. |
| |
| image::{images}/weight_filter_2d.svg[align="center",title="2D Convolution Filter",opts="{imageopts}"] |
| |
| For a 2D weight filter, the phases are stored as layers of a 2D array image. |
| The width and height of the view's subresource range must: be less than or |
| equal to |
| slink:VkPhysicalDeviceImageProcessingPropertiesQCOM::pname:maxWeightFilterDimension. |
| The layers are stored in horizontal phase major order. |
| Expressed as a formula, the layer index for a each filter phase is computed |
| as: |
| |
| [source,c] |
| ---- |
| layerIndex(horizPhase,vertPhase,horizPhaseCount) = (vertPhase * horizPhaseCount) + horizPhase |
| ---- |
| |
| |
| ==== 1D Separable Weight Filters |
| |
| A separable weight filter is a 2D filter that can be specified by two 1D |
| filters in the [eq]#x# and [eq]#y# directions such that their product yields |
| the 2D filter. |
| The following example shows a 2D filter and its associated separable 1D |
| horizontal and vertical filters. |
| |
| image::{images}/weight_filter_1d_separable.svg[align="center",title="Separable 2D Convolution Filter",opts="{imageopts}"] |
| |
| A 1D array image view defined with |
| slink:VkImageViewSampleWeightCreateInfoQCOM and with pname:layerCount equal |
| to '2' describes a separable weight filter. |
| The horizontal weights are specified in slice '0' and the vertical weights |
| in slice '1'. |
| The pname:filterSize and pname:filterCenter specify the size and origin of |
| the of the horizontal and vertical filters. |
| For many use cases, 1D separable filters can offer a performance advantage |
| over 2D filters. |
| |
| For a 1D separable weight filter, the phases are arranged into a 1D array |
| image with two layers. |
| The horizontal weights are stored in layer 0 and the vertical weights in |
| layer 1. |
| Within each layer of the 1D array image, the weights are arranged into |
| groups of 4, and then arranged by phase. |
| Expressed as a formula, the 1D texel offset for each weight within each |
| layer is computed as: |
| |
| [source,c] |
| ---- |
| // Let horizontal weights have a weightIndex of [0, filterSize.width - 1] |
| // Let vertical weights have a weightIndex of [0, filterSize.height - 1] |
| // Let phaseCount be the number of phases in either the vertical or horizontal direction. |
| |
| texelOffset(phaseIndex,weightIndex,phaseCount) = (phaseCount * 4 * (weightIndex / 4)) + (phaseIndex * 4) + (weightIndex % 4) |
| ---- |
| |
| |
| [[textures-weightimage-filterphases]] |
| === Weight Sampling Phases |
| |
| When using weight image sampling, the texture coordinates may not align with |
| a texel center in the sampled image. |
| In this case, the filter weights can be adjusted based on the subpixel |
| location. |
| This is termed "`subpixel filtering`" to indicate that the origin of the |
| filter lies at a subpixel location other than the texel center. |
| Conceptually, this means that the weight filter is positioned such that |
| filter taps do not align with sampled texels exactly. |
| In such a case, modified filter weights may be needed to adjust for the |
| off-center filter taps. |
| Unlike bilinear filtering where the subpixel weights are computed by the |
| implementation, subpixel weight image sampling requires that the per-phase |
| filter weights are pre-computed by the application and stored in an array |
| where each slice of the array is a "`filter phase`". |
| The array is indexed by the implementation based on subpixel positioning. |
| Rather than a single 2D kernel of filter weights, the application provides |
| an array of kernels, one set of filter weights per phase. |
| |
| The number of phases are restricted by following requirements, which apply |
| to both separable and non-separable filters: |
| |
| * The number of phases in the vertical direction, [eq]#phaseCount~vert~#, |
| must: be a power of two (i.e., 1, 2, 4, etc.). |
| * The number of phases in the horizontal direction |
| [eq]#phaseCount~horiz~#, must: equal [eq]#phaseCount~vert~#. |
| * The total number of phases, [eq]#phaseCount~vert~ {times} |
| phaseCount~horiz~#, must: be less than or equal to |
| slink:VkPhysicalDeviceImageProcessingPropertiesQCOM::pname:maxWeightFilterPhases. |
| |
| |
| [[textures-weightimage-sampler]] |
| === Weight Sampler Parameters |
| |
| Weight sampling requires sname:VkSamplerCreateInfo pname:addressModeU and |
| pname:addressModeV must: be set to |
| ename:VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE or |
| ename:VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER. |
| If ename:VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER is used, then the border |
| color must: be set to transparent black. |
| |
| |
| [[textures-weightimage-filteroperation]] |
| === Weight Sampling Operation |
| |
| The 2D unnormalized texel coordinates latexmath:[(u,v)] are transformed by |
| latexmath:[filterCenter] to specify coordinates latexmath:[i_{0}, j_{0}]. |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| i_{0} &= \left\lfloor u - filterCenter_{x} \right\rfloor \\[1em] |
| j_{0} &= \left\lfloor v - filterCenter_{y} \right\rfloor |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| where latexmath:[filterCenter] is specified by |
| slink:VkImageViewSampleWeightCreateInfoQCOM::pname:filterCenter. |
| |
| |
| Two sets of neighboring integer 2D texel coordinates are generated. |
| The first set is used for selecting texels from the sampled image |
| latexmath:[\tau] and the second set used for selecting texels from the |
| weight image latexmath:[w]. |
| The first set of neighboring coordinates are combinations of |
| latexmath:[i_{0}] to latexmath:[i_{filterWidth-1}] and latexmath:[j_{0}] to |
| latexmath:[j_{filterHeight-1}]. |
| The second set of neighboring coordinates are combinations of |
| latexmath:[k_{0}] to latexmath:[k_{filterWidth-1}] and latexmath:[l_{0}] to |
| latexmath:[l_{filterHeight-1}]. |
| The first and second sets each contain latexmath:[(filterWidth \times |
| filterHeight)] of pairs of latexmath:[(i,j)] and latexmath:[(k,l)] |
| coordinates respectively. |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \{i_q\}_{q=0}^{q=filterWidth-1} \quad &= i_{0} + q \\[1em] |
| \{j_q\}_{q=0}^{q=filterHeight-1} \quad &= j_{0} + q \\[1em] |
| \{k_q\}_{q=0}^{q=filterWidth-1} \quad &= q \\[1em] |
| \{l_q\}_{q=0}^{q=filterHeight-1} \quad &= q |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| where latexmath:[filterWidth] and latexmath:[filterHeight] are specified by |
| slink:VkImageViewSampleWeightCreateInfoQCOM::pname:filterSize. |
| |
| Each of the generated integer coordinates latexmath:[({i_q}, {j_q})] is |
| transformed by <<textures-wrapping-operation, texture wrapping operation>>, |
| followed by <<textures-integer-coordinate-validation,integer texel |
| coordinate validation>>, If any coordinate fails coordinate validation, it |
| is a Border Texel and <<textures-texel-replacement,texel replacement>> is |
| performed. |
| |
| |
| The phase index latexmath:[\psi] is computed from the fraction bits of the |
| unnormalized 2D texel coordinates: |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| phaseCount_{h} = phaseCount_{v} &= \sqrt{numPhases} \\[1em] |
| hPhase &= \left\lfloor\mathbin{frac}\left( u \right) \times phaseCount_{h} \right\rfloor \\[1em] |
| vPhase &= \left\lfloor\mathbin{frac}\left( v \right) \times phaseCount_{v} \right\rfloor \\[1em] |
| \psi &= \left(vPhase \times phaseCount_{h}\right) + hPhase |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| where the number of fraction bits retained is |
| latexmath:[\mathbin{log2}\left( numPhases \right)] specified by |
| slink:VkImageViewSampleWeightCreateInfoQCOM::pname:numPhases |
| |
| Each pair of texel coordinates latexmath:[(i,j)] in the first set selects a |
| single texel value latexmath:[\tau_{ij}] from the sampled image. |
| Each pair of texel coordinates latexmath:[(k,l)] in the second set, combined |
| with phaseIndex latexmath:[\psi], selects a single weight from the weight |
| image latexmath:[w(k,l,\psi)] . |
| |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| w(k,l,\psi) &= |
| \begin{cases} |
| w_{kl}[\psi]\quad\text{(}\psi\text{ as layer index)} & \text{for 2D array view (non-separable filter) } \\ |
| weight_{h} \times weight_{v} & \text{for 1D array view (separable filter) } \\ |
| \end{cases} |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| If latexmath:[w] is a 2D array view, then non-separable filtering is |
| specified, and integer coordinates latexmath:[(k,l)] are used to select |
| texels from layer latexmath:[\psi] of latexmath:[(w)]. |
| If latexmath:[w] is a 1D array view, then separable filtering is specified |
| and integer coordinates latexmath:[(k,l)] are transformed to |
| latexmath:[(k_{packed},l_{packed})], and used to select horizontal weight |
| latexmath:[(weight_{h})] and vertical weight latexmath:[(weight_{v})] texels |
| from layer 0 and layer 1 of latexmath:[(w)] respectively. |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| k_{packed} &= \left(phaseCount_{h} \times 4 \times \left\lfloor k / 4 \right\rfloor\right) + \left(hPhase \times 4\right) + \left(k \mathbin{\%} 4\right) \\[1em] |
| l_{packed}& = \left(phaseCount_{v} \times 4 \times \left\lfloor l / 4 \right\rfloor\right) + \left(vPhase \times 4\right) + \left(l \mathbin{\%} 4\right) \\[1em] |
| weight_{h} &= w_{k_{packed}}[0] & \text{(horizontal weights packed in layer 0)} \\[1em] |
| weight_{v} &= w_{l_{packed}}[1] & \text{(vertical weights packed in layer 1)} |
| |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| Where latexmath:[\mathbin{\%}] refers to the integer modulo operator. |
| |
| The values of multiple texels, together with their weights, are combined to |
| produce a filtered value. |
| |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \tau_{weightSampling} &= \sum_{{j=j_0} \atop {l=l_0}}^{j_{blockHeight-1} \atop {l_{blockHeight-1}}}\quad \sum_{{i=i_0}\atop {k=k_0}}^{i_{blockWidth-1} \atop {k_{blockWidth-1}}}w(k,l,\psi)\tau_{ij} \\ |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| When slink:VkSamplerReductionModeCreateInfo::pname:reductionMode is set to |
| ename:VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE, the above summation is |
| used. |
| However, if the reduction mode is ename:VK_SAMPLER_REDUCTION_MODE_MIN or |
| ename:VK_SAMPLER_REDUCTION_MODE_MAX, the process operates on the above |
| values, computing a component-wise minimum or maximum of the texels with |
| non-zero weights. |
| If the reduction mode is ename:VK_SAMPLER_REDUCTION_MODE_MIN or |
| ename:VK_SAMPLER_REDUCTION_MODE_MAX, each latexmath:[w(k,l,\psi)] weight |
| must: be equal to 0.0 or 1.0, otherwise the undefined: values are returned. |
| |
| Finally, the operations described in |
| <<textures-conversion-to-rgba,Conversion to RGBA>> and |
| <<textures-component-swizzle,Component swizzle>> are performed and the final |
| result is returned to the shader. |
| |
| |
| [[textures-blockmatch]] |
| == Block Matching |
| |
| The SPIR-V instruction code:opImageBlockMatchSAD and |
| code:opImageBlockMatchSSD specify texture block matching operations where a |
| block or region of texels within a _target image_ is compared with a |
| same-sized region a _reference image_. |
| The instructions make use of two image views: the _target view_ and the |
| _reference view_. |
| The target view and reference view can be the same view, allowing block |
| matching of two blocks within a single image. |
| |
| Similar to an equivalent code:OpImageFetch instruction, |
| code:opImageBlockMatchSAD and code:opImageBlockMatchSAD specify a code:image |
| and an integer texel code:coordinate which which describes the bottom-left |
| texel of the target block. |
| There are three additional inputs. |
| The code:reference and code:refCoodinate specifies bottom-left texel of the |
| reference block. |
| The code:blockSize specifies the integer width and height of the target and |
| reference blocks to be compared, and must: not be greater than |
| slink:VkPhysicalDeviceImageProcessingPropertiesQCOM.code:maxBlockMatchRegion. |
| |
| ifdef::VK_QCOM_image_processing2[] |
| code:opImageBlockMatchWindowSAD and code:opImageBlockMatchWindowSAD take the |
| same input parameters as the corresponding non-window instructions. |
| The block matching comparison is performed for all pixel values within a 2D |
| window whose dimensions are specified in the sampler. |
| endif::VK_QCOM_image_processing2[] |
| |
| |
| [[textures-blockmatch-sampler]] |
| === Block Matching Sampler Parameters |
| |
| For code:opImageBlockMatchSAD and code:opImageBlockMatchSSD, the input |
| code:sampler must: be created with code:addressModeU and code:addressModeV, |
| equal to ename:VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, or |
| ename:VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER with |
| ename:VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK. |
| The input code:sampler must: be created with code:unnormalizedCoordinates |
| equal to ename:VK_TRUE. |
| The input code:sampler must: be created with pname:components equal to |
| ename:VK_COMPONENT_SWIZZLE_IDENTITY. |
| |
| |
| ifdef::VK_QCOM_image_processing2[] |
| For code:opImageBlockMatchWindowSAD and code:opImageBlockMatchWindowSSD |
| instructions, the code:target sampler must: have been created with |
| slink:VkSamplerBlockMatchWindowCreateInfoQCOM in the code:pNext chain. |
| |
| For code:opImageBlockMatchWindowSAD, code:opImageBlockMatchWindowSSD, |
| code:opImageBlockMatchGatherSAD, or |
| code:opImageBlockMatchGatherSSDinstructions, the input code:sampler must: be |
| created with code:addressModeU and code:addressModeV, equal to |
| ename:VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER with |
| ename:VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK. |
| endif::VK_QCOM_image_processing2[] |
| |
| Other sampler states are ignored. |
| |
| |
| [[textures-blockmatch-filteroperation]] |
| === Block Matching Operation |
| |
| Block matching SPIR-V instructions code:opImageBlockMatchSAD and |
| code:opImageBlockMatchSSD specify two sets of 2D integer texel coordinates: |
| target coordinates latexmath:[(u,v)] and reference coordinates |
| latexmath:[(s,t)]. |
| |
| The coordinates define the bottom-left texel of the target block |
| latexmath:[(i_{0}, j_{0})] and the reference block latexmath:[(k_{0}, |
| l_{0})]. |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| i_{0} &= u \\[1em] |
| j_{0} &= v \\[1em] |
| k_{0} &= s \\[1em] |
| l_{0} &= t |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| For the target block, a set of neighboring integer texel coordinates are |
| generated. |
| The neighboring coordinates are combinations of latexmath:[i_{0}] to |
| latexmath:[i_{blockWidth-1}] and latexmath:[j_{0}] to |
| latexmath:[j_{blockHeight-1}]. |
| The set is of size latexmath:[blockWidth \times blockHeight]. |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \{i_q\}_{q=0}^{q=blockWidth-1} \quad &= i_{0} + q \\[1em] |
| \{j_q\}_{q=0}^{q=blockHeight-1} \quad &= j_{0} + q |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| where latexmath:[blockWidth] and latexmath:[blockHeight] is specified by the |
| code:blockSize operand. |
| |
| If any target integer texel coordinate latexmath:[(i,j)] in the set fails |
| <<textures-integer-coordinate-validation,integer texel coordinate |
| validation>>, then the texel is an invalid texel and |
| <<textures-texel-replacement,texel replacement>> is performed. |
| |
| Similarly for the reference block, a set of neighboring integer texel |
| coordinates are generated. |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \{k_q\}_{q=0}^{q=blockWidth-1} \quad &= k_{0} + q \\[1em] |
| \{l_q\}_{q=0}^{q=blockHeight-1} \quad &= l_{0} + q |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| Each reference texel coordinate latexmath:[(k,l)] in the set must: not fail |
| <<textures-integer-coordinate-validation,integer texel coordinate |
| validation>>. |
| To avoid undefined: behavior, application shader should guarantee that the |
| reference block is fully within the bounds of the reference image. |
| |
| Each pair of texel coordinates latexmath:[(i,j)] in the set selects a single |
| texel value from the target image latexmath:[\tau_{ij}]. |
| Each pair of texel coordinates latexmath:[(k,l)] in the set selects a single |
| texel value from the reference image latexmath:[\upsilon_{kl}]. |
| |
| The difference between target and reference texel values is summed to |
| compute a difference metric. |
| The code:opTextureBlockMatchSAD computes the sum of absolute differences. |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \tau_{SAD} &= \sum_{{j=j_0} \atop {l=l_0}}^{{j_{blockHeight-1}} \atop {l_{blockHeight-1}}} \quad\sum_{{i=i_0} \atop {k=k_0}}^{{i_{blockWidth-1}} \atop {k_{blockWidth-1}}}|\upsilon_{kl}-\tau_{ij}| \\ |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| The code:opImageBlockMatchSSD computes the sum of the squared differences. |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \tau_{SSD} &= \sum_{{j=j_0} \atop {l=l_0}}^{{j_{blockHeight-1}} \atop {l_{blockHeight-1}}} \quad\sum_{{i=i_0} \atop {k=k_0}}^{{i_{blockWidth-1}} \atop {k_{blockWidth-1}}}|\upsilon_{kl}-\tau_{ij}|^2 \\ |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| When slink:VkSamplerReductionModeCreateInfo::pname:reductionMode is set to |
| ename:VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE, the above summation is |
| used. |
| However, if the reduction mode is ename:VK_SAMPLER_REDUCTION_MODE_MIN or |
| ename:VK_SAMPLER_REDUCTION_MODE_MAX, the process operates on the above |
| values, computing a component-wise minimum or maximum of |
| latexmath:[|\upsilon_{kl}-\tau_{ij}|], respectively. |
| For latexmath:[\tau_{SAD}], the minimum or maximum difference is computed |
| and for latexmath:[\tau_{SSD}], the square of the minimum or maximum is |
| computed. |
| |
| Finally, the operations described in |
| <<textures-conversion-to-rgba,Conversion to RGBA>> and |
| <<textures-component-swizzle,Component swizzle>> are performed and the final |
| result is returned to the shader. |
| The component swizzle is specified by the _target image_ descriptor; any |
| swizzle specified by the _reference image_ descriptor is ignored. |
| |
| |
| ifdef::VK_QCOM_image_processing2[] |
| [[textures-blockmatchwindow-filteroperation]] |
| ==== Block Matching Window Operation |
| |
| Window block matching SPIR-V instructions code:opImageBlockMatchWindowSAD |
| and code:opImageBlockMatchWindowSSD specify two sets of 2D integer texel |
| coordinates: target coordinates latexmath:[(u,v)] and reference coordinates |
| latexmath:[(s,t)]. |
| The <<textures-blockmatch-filteroperation,block matching operation>> is |
| performed repeatedly, for multiple sets of target integer coordinates within |
| the specified window. |
| These instructions effectively search a region or "`window`" within the |
| target texture and identify the window coordinates where the minimum or |
| maximum error metric is found. |
| These instructions only support single component image formats. |
| |
| The target coordinates are combinations of coordinates from |
| latexmath:[(u,v)] to latexmath:[(u + windowWidth - 1, v + windowHeight - 1)] |
| where latexmath:[windowHeight] and latexmath:[windowWidth] are specified by |
| slink:VkSamplerBlockMatchWindowCreateInfoQCOM::pname:windowExtent. |
| At each each target coordinate, a |
| <<textures-blockmatch-filteroperation,block matching operation>> is |
| performed, resulting in a difference metric. |
| The the reference coordinate latexmath:[(s,t)] is fixed. |
| The block matching operation is repeated latexmath:[windowWidth \times |
| windowHeight] times. |
| |
| The resulting minimum or maximum error is returned in the R component of the |
| output. |
| The integer window coordinates latexmath:[(x,y)] are returned in the G and B |
| components of the output. |
| The A component is 0. |
| The minimum or maximum behavior is selected by |
| slink:VkSamplerBlockMatchWindowCreateInfoQCOM::pname:windowCompareMode. |
| |
| The following psuedocode describes the operation |
| code:opImageBlockMatchWindowSAD. |
| The pseudocode for code:opImageBlockMatchWindowSSD follows an identical |
| pattern. |
| |
| [source,c] |
| ---- |
| vec4 opImageBlockMatchGatherSAD( sampler2D target, |
| uvec2 targetCoord, |
| samler2D reference, |
| uvec2 refCoord, |
| uvec2 blocksize) { |
| // Two parameters are sourced from the VkSampler associated with |
| // `target`: |
| // compareMode (which can be either `MIN` or `MAX`) |
| // uvec2 window (which defines the search window) |
| |
| minSAD = INF; |
| maxSAD = -INF; |
| uvec2 minCoord; |
| uvec2 maxCoord; |
| |
| for (uint x=0, x<window.width; x++) { |
| for (uint y=0; y<window.height; y++) { |
| float SAD = textureBlockMatchSAD(target, |
| targetCoord + uvec2(x, y), |
| reference, |
| refCoord, |
| blocksize).x; |
| if (SAD < minSAD) { |
| minSAD = SAD; |
| minCoord = uvec2(x,y); |
| } |
| if (SAD > maxSAD) { |
| maxSAD = SAD; |
| maxCoord = uvec2(x,y); |
| } |
| } |
| } |
| if (compareMode==MIN) { |
| return vec4(minSAD, minCoord.x, minCoord.y, 0.0); |
| } else { |
| return vec4(maxSAD, maxCoord.x, maxCoord.y, 0.0); |
| } |
| } |
| ---- |
| |
| |
| [[textures-blockmatchgather-filteroperation]] |
| ==== Block Matching Gather Operation |
| |
| Block matching Gather SPIR-V instructions code:opImageBlockMatchGatherSAD |
| and code:opImageBlockMatchGatherSSD specify two sets of 2D integer texel |
| coordinates: target coordinates latexmath:[(u,v)] and reference coordinates |
| latexmath:[(s,t)]. |
| |
| These instructions perform the <<textures-blockmatch-filteroperation,block |
| matching operation>> 4 times, using integer target coordinates |
| latexmath:[(u,v)], latexmath:[(u+1,v)], latexmath:[(u+2,v)], and |
| latexmath:[(u+3,v)]. |
| The R component from each of those 4 operations is gathered and returned in |
| the R, G, B, and A components of the output respectively. |
| For each block match operation, the reference coordinate is |
| latexmath:[(s,t)]. |
| For each block match operation, only the R component of the target and |
| reference images are compared. |
| The following psuedocode describes the operation opImageBlockMatchGatherSAD. |
| The pseudocode for opImageBlockMatchGatherSSD follows an identical pattern. |
| |
| [source,c] |
| ---- |
| vec4 opImageBlockMatchGatherSAD(sampler2D target, |
| uvec2 targetCoord, |
| samler2D reference, |
| uvec2 refCoord, |
| uvec2 blocksize) { |
| vec4 out; |
| for (uint x=0, x<4; x++) { |
| float SAD = textureBlockMatchSAD(target, |
| targetCoord + uvec2(x, 0), |
| reference, |
| refCoord, |
| blocksize).x; |
| if (x == 0) { |
| out.x = SAD; |
| } |
| if (x == 1) { |
| out.y = SAD; |
| } |
| if (x == 2) { |
| out.z = SAD; |
| } |
| if (x == 3) { |
| out.w = SAD; |
| } |
| } |
| return out; |
| } |
| ---- |
| endif::VK_QCOM_image_processing2[] |
| |
| |
| [[textures-boxfilter]] |
| == Box Filter Sampling |
| |
| The SPIR-V instruction code:OpImageBoxFilterQCOM specifies texture box |
| filtering operation where a weighted average of a region of texels is |
| computed, with the weights proportional to the coverage of each of the |
| texels. |
| |
| In addition to the inputs that would be accepted by an equivalent |
| code:OpImageSample* instruction, code:OpImageBoxFilterQCOM accepts one |
| additional input, code:boxSize which specifies the width and height in |
| texels of the region to be averaged. |
| |
| The figure below shows an example of using code:OpImageBoxFilterQCOM to |
| sample from a [eq]#8 {times} 4# texel two-dimensional image, with |
| unnormalized texture coordinates [eq]#(4.125, 2.625)# and code:boxSize of |
| [eq]#(2.75, 2.25)#. |
| The filter will read 12 texel values and compute a weights based portion of |
| of each texel covered by the box. |
| |
| [[textures-box-filter-diagrams]] |
| image::{images}/vulkantexture_boxFilter.svg[align="center",title="Box Filter Sampling Example",opts="{imageopts}"] |
| |
| If code:boxSize has height and width both equal to 1.0, then this |
| instruction will behave as traditional bilinear filtering. |
| The code:boxSize parameter must: be greater than or equal to 1.0 and must: |
| not be greater than |
| slink:VkPhysicalDeviceImageProcessingPropertiesQCOM.code:maxBoxFilterBlockSize. |
| |
| |
| [[textures-boxfilter-sampler]] |
| === Box Filter Sampler Parameters |
| |
| The input code:sampler must: be created with code:addressModeU and |
| code:addressModeV, equal to ename:VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, or |
| ename:VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER with |
| ename:VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK. |
| |
| |
| [[textures-boxfilter-filteroperation]] |
| === Box Filter Operation |
| |
| The 2D unnormalized texel coordinates latexmath:[(u,v)] are transformed by |
| latexmath:[boxSize] to specify integer texel coordinates latexmath:[(i_{0}, |
| j_{0})] of the bottom left texel for the filter. |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| i_{0} &= \left\lfloor u - \frac{boxWidth}{2} \right\rfloor \\[1em] |
| j_{0} &= \left\lfloor v - \frac{boxHeight}{2} \right\rfloor |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| where latexmath:[boxWidth] and latexmath:[boxHeight] are specified by the |
| code:(x,y) components of the code:boxSize operand. |
| |
| The filter dimensions latexmath:[(filterWidth \times filterHeight)] are |
| computed from the fractional portion of the latexmath:[(u,v)] coordinates |
| and the latexmath:[boxSize]. |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| startFracU &= \mathbin{frac}\left(u - \frac{boxWidth}{2} \right) \\[1em] |
| startFracV &= \mathbin{frac}\left(v - \frac{boxHeight}{2} \right) \\[1em] |
| endFracU &= \mathbin{frac}\left( startFracU + boxWidth \right) \\[1em] |
| endFracV &= \mathbin{frac}\left( startFracV + boxHeight \right) \\[1em] |
| filterWidth &= \left\lceil startFracU + boxWidth \right\rceil \\[1em] |
| filterHeight &= \left\lceil startFracV + boxHeight \right\rceil |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| where the number of fraction bits retained by latexmath:[frac()] is |
| specified by sname:VkPhysicalDeviceLimits::pname:subTexelPrecisionBits. |
| |
| A set of neighboring integer texel coordinates are generated. |
| The neighboring coordinates are combinations of latexmath:[i_{0}] to |
| latexmath:[i_{filterWidth-1}] and latexmath:[j_{0}] to |
| latexmath:[j_{filterHeight-1}], with latexmath:[i_{0}, j_{0}] being the |
| top-left coordinate of this set. |
| The set is of size latexmath:[(filterWidth \times filterHeight)]. |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \{i_q\}_{q=0}^{q=filterWidth-1} \quad &= i_{0} + q \\[1em] |
| \{j_q\}_{q=0}^{q=filterHeight-1} \quad &= j_{0} + q |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| Each of the generated integer coordinates latexmath:[({i_q}, {j_q})] is |
| transformed by <<textures-wrapping-operation, texture wrapping operation>>, |
| followed by <<textures-integer-coordinate-validation,integer texel |
| coordinate validation>>, If any coordinate fails coordinate validation, it |
| is a Border Texel and <<textures-texel-replacement,texel replacement>> is |
| performed. |
| |
| Horizontal weights latexmath:[horizWeight_{0}] to |
| latexmath:[horizWeight_{boxWidth-1}] and vertical weights |
| latexmath:[vertWeight_{0}] to latexmath:[vertWeight_{boxHeight-1}] are |
| computed. |
| Texels that are fully covered by the box will have a horizontal and vertical |
| weight of 1. |
| Texels partially covered by the box will have will have a reduced weights |
| proportional to the coverage. |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| horizWeight_{i} &= |
| \begin{cases} |
| \left(1-startFracU \right), & \text{for } (i == 0) \\ |
| \left(endFracU \right), & \text{for } (i == filterWidth-1) \text{ and } (endFracU != 0) \\ |
| \left(1\right), & \text{otherwise} \\ |
| \end{cases} |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| vertWeight_{j} &= |
| \begin{cases} |
| \left(1-startFracV \right), & \text{for } (j == 0) \\ |
| \left(endFracV \right), & \text{for } (j == filterHeight-1) \text{ and } (endFracV !=0) \\ |
| \left(1\right), & \text{otherwise} \\ |
| \end{cases} |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| |
| The values of multiple texels, together with their horizontal and vertical |
| weights, are combined to produce a box filtered value. |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \tau_{boxFilter} &= \frac{1}{boxHeight \times boxWidth} \sum_{j=j_0}^{j_{filterHeight-1}}\quad\sum_{i=i_0}^{i_{filterWidth-1}}(horizWeight_i)(vertWeight_j)\tau_{ij} \\ |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| When slink:VkSamplerReductionModeCreateInfo::pname:reductionMode is set to |
| ename:VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE, the above summation is |
| used. |
| However, if the reduction mode is ename:VK_SAMPLER_REDUCTION_MODE_MIN or |
| ename:VK_SAMPLER_REDUCTION_MODE_MAX, the process operates on the above |
| values, computing a component-wise minimum or maximum of the texels. |
| |
| endif::VK_QCOM_image_processing[] |
| |
| |
| [[textures-instructions]] |
| == Image Operation Steps |
| |
| Each step described in this chapter is performed by a subset of the image |
| instructions: |
| |
| * Texel Input Validation Operations, Format Conversion, Texel Replacement, |
| Conversion to RGBA, and Component Swizzle: Performed by all instructions |
| except code:OpImageWrite. |
| * Depth Comparison: Performed by code:OpImage*Dref instructions. |
| * All Texel output operations: Performed by code:OpImageWrite. |
| * Projection: Performed by all code:OpImage*Proj instructions. |
| * Derivative Image Operations, Cube Map Operations, Scale Factor |
| Operation, LOD Operation and Image Level(s) Selection, and Texel |
| Anisotropic Filtering: Performed by all code:OpImageSample* and |
| code:OpImageSparseSample* instructions. |
| * (s,t,r,q,a) to (u,v,w,a) Transformation, Wrapping, and (u,v,w,a) to |
| (i,j,k,l,n) Transformation And Array Layer Selection: Performed by all |
| code:OpImageSample, code:OpImageSparseSample, and code:OpImage*Gather |
| instructions. |
| * Texel Gathering: Performed by code:OpImage*Gather instructions. |
| ifdef::VK_NV_shader_image_footprint[] |
| * Texel Footprint Evaluation: Performed by code:OpImageSampleFootprint |
| instructions. |
| endif::VK_NV_shader_image_footprint[] |
| * Texel Filtering: Performed by all code:OpImageSample* and |
| code:OpImageSparseSample* instructions. |
| * Sparse Residency: Performed by all code:OpImageSparse* instructions. |
| ifdef::VK_QCOM_image_processing[] |
| * (s,t,r,q,a) to (u,v,w,a) Transformation, Wrapping, and Weight Image |
| Sampling: Performed by code:OpImageWeightedSample* instructions. |
| * (s,t,r,q,a) to (u,v,w,a) Transformation, Wrapping, and Block Matching: |
| Performed by code:opImageBlockMatch* instructions. |
| * (s,t,r,q,a) to (u,v,w,a) Transformation, Wrapping, and Box Filter |
| Sampling: Performed by code:OpImageBoxFilter* instructions. |
| endif::VK_QCOM_image_processing[] |
| |
| |
| [[textures-queries]] |
| == Image Query Instructions |
| |
| |
| === Image Property Queries |
| |
| code:OpImageQuerySize, code:OpImageQuerySizeLod, code:OpImageQueryLevels, |
| and code:OpImageQuerySamples query properties of the image descriptor that |
| would be accessed by a shader image operation. |
| ifdef::VK_EXT_robustness2[] |
| They return 0 if the bound descriptor is a null descriptor. |
| endif::VK_EXT_robustness2[] |
| |
| code:OpImageQuerySizeLod returns the size of the image level identified by |
| the code:Level code:of code:Detail operand. |
| If that level does not exist in the image, |
| ifdef::VK_EXT_robustness2[and the descriptor is not null,] |
| then the value returned is undefined:. |
| |
| |
| === Lod Query |
| |
| code:OpImageQueryLod returns the Lod parameters that would be used in an |
| image operation with the given image and coordinates. |
| ifdef::VK_EXT_robustness2[] |
| If the descriptor that would be accessed is a null descriptor then |
| [eq]#(0,0)# is returned. |
| endif::VK_EXT_robustness2[] |
| ifdef::VK_EXT_robustness2[Otherwise, the] |
| ifndef::VK_EXT_robustness2[The] |
| steps described in this chapter are performed as if for |
| code:OpImageSampleImplicitLod, up to <<textures-lod-and-scale-factor>>. |
| The return value is the vector [eq]#({lambda}', d~l~)#. |
| These values may: be subject to implementation-specific maxima and minima |
| for very large, out-of-range values. |