| // Copyright (c) 2015-2018 Khronos Group. This work is licensed under a |
| // Creative Commons Attribution 4.0 International License; see |
| // http://creativecommons.org/licenses/by/4.0/ |
| |
| [[textures]] |
| = Image Operations |
| |
| == Image Operations Overview |
| |
| Image Operations are steps performed by SPIR-V image instructions, where |
| those instructions which take an code:OpTypeImage (representing a |
| sname:VkImageView) or code:OpTypeSampledImage (representing a |
| (sname:VkImageView, sname:VkSampler) pair) and texel coordinates as |
| operands, and return a value based on one or more neighboring texture |
| elements (_texels_) in the image. |
| |
| [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. |
| ==== |
| |
| SPIR-V Image Instructions include the following functionality: |
| |
| * 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*code:Gather and code:OpImageSparse*code: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. |
| * Instructions with code:Dref in the name apply |
| <<textures-depth-compare-operation,depth comparison>> on the texel |
| values. |
| * Instructions with code:Sparse in the name additionally return a |
| <<textures-sparse-residency,sparse residency>> code. |
| |
| |
| === 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, 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 (s, [t,] [r,] q) |
| with t and r being conditionally present based on the code:Dim of the image. |
| For non-code:Proj instructions, the coordinates are (s [,t] [,r] [,a]), with |
| t and r being conditionally present based on the code:Dim of the image and 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)#, and the |
| first four in that order have the same meanings as unnormalized texel |
| coordinates. |
| They are extracted from the SPIR-V operand in order [eq]#(i, [,j], [,k], |
| [,l])#, with [eq]#j# and [eq]#k# conditionally present based on the code:Dim |
| of the image, and l conditionally present based on the code:Arrayed property |
| of the image. |
| n is the sample index and is taken from the code:Sample image operand. |
| |
| For all coordinate types, unused coordinates are assigned a value of zero. |
| |
| [[textures-texel-coordinate-systems-diagrams]] |
| [%inline] |
| image::images/vulkantexture0.svg[align="center",title="Texel Coordinate Systems"] |
| 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, left to right. |
| ** The [eq]#t# coordinate goes from 0.0 to 1.0, top to bottom. |
| * Unnormalized texel coordinates: |
| ** The [eq]#u# coordinate goes from -1.0 to 9.0, left to right. |
| The [eq]#u# coordinate within the range 0.0 to 8.0 is within the image, |
| otherwise it is within the border. |
| ** The [eq]#v# coordinate goes from -1.0 to 5.0, top to bottom. |
| The [eq]#v# coordinate within the range 0.0 to 4.0 is within the image, |
| otherwise it is within the border. |
| * Integer texel coordinates: |
| ** The [eq]#i# coordinate goes from -1 to 8, left to right. |
| The [eq]#i# coordinate within the range 0 to 7 addresses texels within |
| the image, otherwise it addresses a border texel. |
| ** The [eq]#j# coordinate goes from -1 to 5, top to bottom. |
| The [eq]#j# coordinate within the range 0 to 3 addresses texels within |
| the image, otherwise it addresses a border texel. |
| * 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 weights [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 channels, [eq]#{DeltaUpper}~i~# and |
| [eq]#{DeltaUpper}~j~# are relative to the resolution of the |
| highest-resolution channel, and therefore may be divided by two relative to |
| the unnormalized coordinate space of the lower-resolution channels. |
| ==== |
| endif::VK_VERSION_1_1,VK_KHR_sampler_ycbcr_conversion[] |
| |
| [%inline] |
| image::images/vulkantexture1.svg[align="center",title="Texel Coordinate Systems"] |
| |
| 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'#. |
| |
| |
| == 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: |
| |
| :: [eq]#red~clamped~ = max(0, min(sharedexp~max~, red))# |
| :: [eq]#green~clamped~ = max(0, min(sharedexp~max~, green))# |
| :: [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 |
| ==== |
| [eq]#NaN#, if supported, is handled as in <<ieee-754,IEEE 754-2008>> |
| `minNum()` and `maxNum()`. |
| That is the result is a [eq]#NaN# is mapped to zero. |
| ==== |
| |
| The largest clamped component, [eq]#max~clamped~# is determined: |
| |
| :: [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: |
| |
| :: latexmath:[red = red_{shared} \times {2^{(exp_{shared}-B-N)}}] |
| :: latexmath:[green = green_{shared} \times {2^{(exp_{shared}-B-N)}}] |
| :: latexmath:[blue = blue_{shared} \times {2^{(exp_{shared}-B-N)}}] |
| |
| Where: |
| |
| :: [eq]#N = 9# (number of mantissa bits per component) |
| :: [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>> |
| ** <<textures-layout-validation,Layout validation>> |
| * <<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,Y'C~B~C~R~ 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 |
| Y'C~B~C~R~ conversion>> occurs. |
| endif::VK_VERSION_1_1,VK_KHR_sampler_ycbcr_conversion[] |
| |
| |
| [[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. |
| There are a number of 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. |
| * 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 ename:VK_COMPONENT_SWIZZLE_IDENTITY. |
| * The elink:VkImageLayout of any subresource in the image view does not |
| match that specified in slink:VkDescriptorImageInfo::pname:imageLayout |
| used to write the image descriptor. |
| * If the instruction is code:OpImageRead or code:OpImageSparseRead and the |
| pname:shaderStorageImageReadWithoutFormat feature is not enabled, or the |
| instruction is code:OpImageWrite and the |
| pname:shaderStorageImageWriteWithoutFormat feature is not enabled, then |
| the SPIR-V Image Format must: be <<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. |
| * The SPIR-V instruction is one of the code:OpImage*code:Dref* |
| instructions and the sampler pname:compareEnable is ename:VK_FALSE |
| * The SPIR-V instruction is not one of the code:OpImage*code:Dref* |
| instructions and the sampler pname:compareEnable is ename:VK_TRUE |
| * The SPIR-V instruction is one of the code:OpImage*code: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. |
| * 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. |
| |
| ifdef::VK_VERSION_1_1,VK_KHR_sampler_ycbcr_conversion[] |
| Only code:OpImageSample* and code:OpImageSparseSample* can: be used with a |
| sampler that enables <<samplers-YCbCr-conversion,sampler Y'C~B~C~R~ |
| conversion>>. |
| |
| code:OpImageFetch, code:OpImageSparseFetch, code:OpImage*code:Gather, and |
| code:OpImageSparse*code:Gather must: not be used with a sampler that enables |
| <<samplers-YCbCr-conversion,sampler Y\'C~B~C~R~ conversion>>. |
| |
| The code:ConstOffset and code:Offset operands must: not be used with a |
| sampler that enables <<samplers-YCbCr-conversion,sampler Y'C~B~C~R~ |
| 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 |
| |
| :: [eq]#0 {leq} i < w~s~# |
| :: [eq]#0 {leq} j < h~s~# |
| :: [eq]#0 {leq} k < d~s~# |
| :: [eq]#0 {leq} l < layers# |
| :: [eq]#0 {leq} n < samples# |
| |
| where: |
| |
| :: [eq]#w~s~ =# width of the image level |
| :: [eq]#h~s~ =# height of the image level |
| :: [eq]#d~s~ =# depth of the image level |
| :: [eq]#layers =# number of layers in the image |
| :: [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, |
| + |
| 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 on the borders along the edges and |
| corners of a cube map image, and <<textures-cubemapedge, Cube map edge |
| handling>> is performed. |
| |
| |
| [[textures-cubemapedge]] |
| ==== Cube Map Edge Handling |
| |
| If the texel coordinates lie on the borders along the edges and corners of a |
| cube map image, the following steps are performed. |
| Note that this only occurs when using ename:VK_FILTER_LINEAR 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 along the border in either only [eq]#i# or only |
| [eq]#j# |
| + |
| then the texel lies along an edge, so 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 along the border in both [eq]#i# and [eq]#j# |
| + |
| then the texel lies at a corner and 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, subject to the constraint that if the three available samples have |
| the same value, the replacement texel also has that value. |
| |
| |
| [[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>> when the image is sampled with |
| <<samplers-YCbCr-conversion,sampler Y'C~B~C~R~ conversion>>, the result of |
| texel reads is undefined. |
| |
| 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 |
| <<features-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 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. |
| |
| 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]] |
| .Border Color [eq]#B# |
| [options="header",cols="60%,40%"] |
| |==== |
| | Sampler pname:borderColor | Corresponding Border Color |
| | ename:VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK | [eq]#B = (0.0, 0.0, 0.0, 0.0)# |
| | ename:VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK | [eq]#B = (0.0, 0.0, 0.0, 1.0)# |
| | ename:VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE | [eq]#B = (1.0, 1.0, 1.0, 1.0)# |
| | ename:VK_BORDER_COLOR_INT_TRANSPARENT_BLACK | [eq]#B = (0, 0, 0, 0)# |
| | ename:VK_BORDER_COLOR_INT_OPAQUE_BLACK | [eq]#B = (0, 0, 0, 1)# |
| | ename:VK_BORDER_COLOR_INT_OPAQUE_WHITE | [eq]#B = (1, 1, 1, 1)# |
| |==== |
| |
| [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="80%",options="header"] |
| |==== |
| | Texel Aspect or Format | Component Assignment |
| | Depth aspect | [eq]#D = B~r~# |
| | Stencil aspect | [eq]#S = B~r~# |
| | One component color format | [eq]#C~r~ = B~r~# |
| | Two component color format | [eq]#C~rg~ = (B~r~,B~g~)# |
| | Three component color format| [eq]#C~rgb~ = (B~r~,B~g~,B~b~)# |
| | Four component color format | [eq]#C~rgba~ = (B~r~,B~g~,B~b~,B~a~)# |
| |==== |
| |
| 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-features-robustBufferAccess,pname:robustBufferAccess feature>>. |
| |
| 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 a code:Dref |
| instruction, a depth comparison is performed. |
| The value of the result [eq]#D# is [eq]#1.0# if the result of the compare |
| operation is [eq]#true#, and [eq]#0.0# otherwise. |
| The compare operation is selected by the pname:compareOp member of the |
| sampler. |
| |
| [latexmath] |
| +++++++++++++++++++ |
| \begin{aligned} |
| D & = 1.0 & |
| \begin{cases} |
| D_{\textit{ref}} \leq D & \text{for LEQUAL} \\ |
| D_{\textit{ref}} \geq D & \text{for GEQUAL} \\ |
| D_{\textit{ref}} < D & \text{for LESS} \\ |
| D_{\textit{ref}} > D & \text{for GREATER} \\ |
| D_{\textit{ref}} = D & \text{for EQUAL} \\ |
| D_{\textit{ref}} \neq D & \text{for NOTEQUAL} \\ |
| \textit{true} & \text{for ALWAYS} \\ |
| \textit{false} & \text{for NEVER} |
| \end{cases} \\ |
| D & = 0.0 & \text{otherwise} |
| \end{aligned} |
| +++++++++++++++++++ |
| |
| where, in the depth comparison: |
| |
| :: [eq]#D~ref~ = shaderOp.D~ref~# (from optional: SPIR-V operand) |
| :: [eq]#D# (texel depth value) |
| |
| |
| [[textures-conversion-to-rgba]] |
| === Conversion to RGBA |
| |
| The texel is expanded from one, two, or three to four components based on |
| the image base color: |
| |
| [[textures-texel-color-rgba-conversion-table]] |
| .Texel Color After Conversion To RGBA |
| [options="header"] |
| |==== |
| | Texel Aspect or Format | RGBA Color |
| | Depth aspect | [eq]#C~rgba~ = (D,0,0,one)# |
| | Stencil aspect | [eq]#C~rgba~ = (S,0,0,one)# |
| | One component color format | [eq]#C~rgba~ = (C~r~,0,0,one)# |
| | Two component color format | [eq]#C~rgba~ = (C~rg~,0,one)# |
| | Three component color format| [eq]#C~rgba~ = (C~rgb~,one)# |
| | Four component color format | [eq]#C~rgba~ = C~rgba~# |
| |==== |
| |
| 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 Y'C~B~C~R~ 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 Y'C~B~C~R~ conversion>> if sampler |
| Y'C~B~C~R~ 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 |
| and one for any components. |
| It is defined as follows for the R component, and operates similarly for the |
| other components. |
| |
| |
| [latexmath] |
| +++++++++++++++++++ |
| \begin{aligned} |
| C'_{rgba}[R] & = |
| \begin{cases} |
| C_{rgba}[R] & \text{for RED swizzle} \\ |
| C_{rgba}[G] & \text{for GREEN swizzle} \\ |
| C_{rgba}[B] & \text{for BLUE swizzle} \\ |
| C_{rgba}[A] & \text{for ALPHA swizzle} \\ |
| 0 & \text{for ZERO swizzle} \\ |
| one & \text{for ONE swizzle} \\ |
| C_{rgba}[R] & \text{for IDENTITY swizzle} |
| \end{cases} |
| \end{aligned} |
| +++++++++++++++++++ |
| |
| where: |
| |
| [latexmath] |
| +++++++++++++++++++ |
| \begin{aligned} |
| C_{rgba}[R] & \text{is the RED component} \\ |
| C_{rgba}[G] & \text{is the GREEN component} \\ |
| C_{rgba}[B] & \text{is the BLUE component} \\ |
| C_{rgba}[A] & \text{is the ALPHA component} \\ |
| one & = 1.0\text{f} & \text{for floating point components} \\ |
| one & = 1 & \text{for integer components} |
| \end{aligned} |
| +++++++++++++++++++ |
| |
| For each component this is applied to, the |
| ename:VK_COMPONENT_SWIZZLE_IDENTITY swizzle selects the corresponding |
| component from [eq]#C~rgba~#. |
| |
| If the border color is one of the etext:VK_BORDER_COLOR_*_OPAQUE_BLACK enums |
| and the elink:VkComponentSwizzle is not ename:VK_COMPONENT_SWIZZLE_IDENTITY |
| for all components (or the |
| <<resources-image-views-identity-mappings,equivalent identity mapping>>), |
| the value of the texel after swizzle is undefined. |
| |
| |
| [[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 |
| channels at lower spatial resolution than the luma channel. |
| 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 channel dominates the eye's sensitivity to light intensity and the |
| spatial sensitivity to color introduced by red and blue is lower. |
| |
| Lower-resolution channels are "`downsampled`" by resizing them to a lower |
| spatial resolution than the channel representing luminance. |
| 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 |
| channels 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 Y'C~B~C~R~ conversion. |
| |
| The following diagrams show the relationship between unnormalized (_u_,_v_) |
| coordinates and (_i_,_j_) integer texel positions in the luma channel (shown |
| in black, with circles showing integer sample positions) and the texel |
| coordinates of reduced-resolution chroma channels, 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. |
| ==== |
| |
| [%inline] |
| image::images/chromasamples_422_cosited.svg[align="center",title="422 downsampling, xChromaOffset=COSITED_EVEN"] |
| |
| [%inline] |
| image::images/chromasamples_422_midpoint.svg[align="center",title="422 downsampling, xChromaOffset=MIDPOINT"] |
| |
| [%inline] |
| image::images/chromasamples_420_xcosited_ycosited.svg[align="center",title="420 downsampling, xChromaOffset=COSITED_EVEN, yChromaOffset=COSITED_EVEN"] |
| |
| [%inline] |
| image::images/chromasamples_420_xmidpoint_ycosited.svg[align="center",title="420 downsampling, xChromaOffset=MIDPOINT, yChromaOffset=COSITED_EVEN"] |
| |
| [%inline] |
| image::images/chromasamples_420_xcosited_ymidpoint.svg[align="center",title="420 downsampling, xChromaOffset=COSITED_EVEN, yChromaOffset=MIDPOINT"] |
| |
| [%inline] |
| image::images/chromasamples_420_xmidpoint_ymidpoint.svg[align="center",title="420 downsampling, xChromaOffset=MIDPOINT, yChromaOffset=MIDPOINT"] |
| |
| 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 sname: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 sname: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 channels are reduced in resolution in just |
| width by a factor of two relative to the G channel (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(\lfloor{i\times 0.5}\rfloor, j)[level] \\ |
| \tau_B'(i, j) & = \tau_B(\lfloor{i\times 0.5}\rfloor, j)[level] |
| \end{aligned} |
| ++++++++++++++ |
| |
| ** If the format's R and B channels are reduced in resolution in width |
| and height by a factor of two relative to the G channel (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(\lfloor{i\times 0.5}\rfloor, \lfloor{j\times 0.5}\rfloor)[level] \\ |
| \tau_B'(i, j) & = \tau_B(\lfloor{i\times 0.5}\rfloor, \lfloor{j\times 0.5}\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 channels are reduced in resolution in just |
| width by a factor of two relative to the G channel (i.e. this is a |
| "`422`" format): |
| *** If pname:xChromaOffset is ename:VK_CHROMA_LOCATION_COSITED_EVEN: |
| + |
| [latexmath] |
| +++++ |
| \tau_{RB}'(i,j) = \begin{cases} |
| \tau_{RB}(\lfloor{i\times 0.5}\rfloor,j)[level], & 0.5 \times i = \lfloor{0.5 \times i}\rfloor\\ |
| 0.5\times\tau_{RB}(\lfloor{i\times 0.5}\rfloor,j)[level] + \\ |
| 0.5\times\tau_{RB}(\lfloor{i\times 0.5}\rfloor + 1,j)[level], & 0.5 \times i \neq \lfloor{0.5 \times i}\rfloor |
| \end{cases} |
| +++++ |
| + |
| *** If pname:xChromaOffset is ename:VK_CHROMA_LOCATION_MIDPOINT: |
| + |
| [latexmath] |
| +++++ |
| \tau_{RB}(i,j)' = \begin{cases} |
| 0.25 \times \tau_{RB}(\lfloor{i\times 0.5}\rfloor - 1,j)[level] + \\ |
| 0.75 \times \tau_{RB}(\lfloor{i\times 0.5}\rfloor,j)[level], & 0.5 \times i = \lfloor{0.5 \times i}\rfloor\\ |
| 0.75 \times \tau_{RB}(\lfloor{i\times 0.5}\rfloor,j)[level] + \\ |
| 0.25 \times \tau_{RB}(\lfloor{i\times 0.5}\rfloor + 1,j)[level], & 0.5 \times i \neq \lfloor{0.5 \times i}\rfloor |
| \end{cases} |
| +++++ |
| |
| ** If the format's R and B channels are reduced in resolution in width and |
| height by a factor of two relative to the G channel (i.e. this is a |
| "`420`" format), a similar relationship applies. |
| Due to the number of options, these formulae are expressed more |
| concisely as follows: |
| + |
| [width="30%",options="header",cols="5,1"] |
| |==== |
| | pname:xChromaOffset | δ~i~ |
| | etext:COSITED_EVEN | 0 |
| | etext:MIDPOINT | 0.5 |
| |==== |
| + |
| [width="30%",options="header",cols="5,1"] |
| |==== |
| | pname:yChromaOffset | δ~j~ |
| | etext:COSITED_EVEN | 0 |
| | etext:MIDPOINT | 0.5 |
| |==== |
| + |
| [latexmath] |
| +++++ |
| \begin{aligned} |
| \tau_{RB}'(i,j) = &\\ |
| &\tau_{RB}(\lfloor 0.5\times(i-\delta_i)\rfloor, \lfloor 0.5\times(j-\delta_j)\rfloor)[level] |
| && \times (1 - (0.5\times(i-\delta_i) - \lfloor 0.5\times(i-\delta_i)\rfloor)) |
| && \times (1 - (0.5\times(j-\delta_j) - \lfloor 0.5\times(j-\delta_j)\rfloor)) +\\ |
| &\tau_{RB}(1+\lfloor 0.5\times(i-\delta_i)\rfloor, \lfloor 0.5\times(j-\delta_j)\rfloor)[level] |
| && \times (0.5\times(i-\delta_i) - \lfloor 0.5\times(i-\delta_i)\rfloor) |
| && \times (1 - (0.5\times(j-\delta_j) - \lfloor 0.5\times(j-\delta_j)\rfloor)) +\\ |
| &\tau_{RB}(\lfloor 0.5\times(i-\delta_i)\rfloor, 1+\lfloor 0.5\times(j-\delta_j)\rfloor)[level] |
| && \times (1 - (0.5\times(i-\delta_i) - \lfloor 0.5\times(i-\delta_i)\rfloor)) |
| && \times (0.5\times(j-\delta_j) - \lfloor 0.5\times(j-\delta_j)\rfloor) +\\ |
| &\tau_{RB}(1+\lfloor 0.5\times(i-\delta_i)\rfloor, 1+\lfloor 0.5\times(j-\delta_j)\rfloor)[level] |
| && \times (0.5\times(i-\delta_i) - \lfloor 0.5\times(i-\delta_i)\rfloor) |
| && \times (0.5\times(j-\delta_j) - \lfloor 0.5\times(j-\delta_j)\rfloor) |
| \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 channels 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 channel |
| (such that, for example, the sample coordinates are divided by two if the |
| channel has a downsample factor of two relative to the luma channel): |
| |
| [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 Y'C~B~C~R~ Conversion |
| |
| Sampler Y'C~B~C~R~ conversion performs the following operations, which an |
| implementation may: combine into a single mathematical operation: |
| |
| * <<textures-sampler-YCbCr-conversion-rangeexpand,Sampler Y'C~B~C~R~ Range |
| Expansion>> |
| * <<textures-sampler-YCbCr-conversion-modelconversion,Sampler Y'C~B~C~R~ |
| Model Conversion>> |
| |
| [[textures-sampler-YCbCr-conversion-rangeexpand]] |
| ==== Sampler Y'C~B~C~R~ Range Expansion |
| |
| Sampler Y'C~B~C~R~ range expansion is applied to color channel values after |
| all texel input operations which are not specific to sampler Y'C~B~C~R~ |
| conversion. |
| For example, the input values to this stage have been converted using the |
| normal <<textures-format-conversion,format conversion>> rules. |
| |
| Sampler Y'C~B~C~R~ 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 channel values output by the <<textures-component-swizzle,Component |
| Swizzle>> defined by the pname:components member of |
| slink:VkSamplerYcbcrConversionCreateInfo. |
| Range expansion applies independently to each channel of the image. |
| For the purposes of range expansion and Y'C~B~C~R~ model conversion, the R |
| and B channels contain color difference (chroma) values and the G channel |
| contains luma. |
| The A channel is not modified by sampler Y'C~B~C~R~ range expansion. |
| |
| The range expansion to be applied is defined by the pname:ycbcrRange member |
| of the sname: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 |
| <<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 |
| <<data-format,Khronos Data Format Specification>>. |
| ==== |
| * _n_ is the bit-depth of the channels 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' 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 Y'C~B~C~R~ 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 channels 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; Y'C~B~C~R~ range expansion is also ignored. |
| ename:VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY:: |
| The color channels are not modified by the color model conversion and are |
| assumed to be treated as though in Y'C~B~C~R~ form both in memory and in |
| the shader; Y'C~B~C~R~ range expansion is applied to the channels as for |
| other Y'C~B~C~R~ models, with the vector (C~R~,Y',C~B~,A) provided to the |
| shader. |
| ename:VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709:: |
| The color channels are transformed from a Y'C~B~C~R~ representation to an |
| R'G'B' representation as described in the "`BT.709 Y'C~B~C~R~ conversion`" |
| section of the <<data-format,Khronos Data Format Specification>>. |
| ename:VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601:: |
| The color channels are transformed from a Y'C~B~C~R~ representation to an |
| R'G'B' representation as described in the "`BT.601 Y'C~B~C~R~ conversion`" |
| section of the <<data-format,Khronos Data Format Specification>>. |
| ename:VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020:: |
| The color channels are transformed from a Y'C~B~C~R~ representation to an |
| R'G'B' representation as described in the "`BT.2020 Y'C~B~C~R~ |
| conversion`" section of the <<data-format,Khronos Data Format |
| Specification>>. |
| |
| In this operation, each output channel is dependent on each input channel. |
| |
| An implementation may: clamp the R'G'B' 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 channel 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/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 Y'C~B~C~R~ |
| conversion>> at this location. |
| * For a pname:minFilter/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 Y'C~B~C~R~ |
| conversion>> at each of these locations. |
| . Convert the non-linear AR'G'B' outputs of the Y'C~B~C~R~ 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 |
| variation from "`correct`" results are subtle for most content, the |
| application author should determine whether a more costly implementation is |
| strictly necessary. |
| Note that if pname:chromaFilter and pname:minFilter/pname:magFilter are both |
| ename:VK_FILTER_NEAREST, these operations are redundant and sampling using |
| <<samplers-YCbCr-conversion,sampler Y'C~B~C~R~ 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-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 compatible with the |
| sname:VkImageView's pname:format, the effect of the write on the image |
| view's memory is undefined, but the write must: not access memory outside of |
| the image view. |
| |
| |
| [[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. |
| Any unused components are ignored. |
| |
| Each component is converted based on its type and size (as defined in the |
| <<features-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. |
| |
| |
| == Derivative Operations |
| |
| SPIR-V derivative instructions include code:OpDPdx, code:OpDPdy, |
| code:OpDPdxFine, code:OpDPdyFine, code:OpDPdxCoarse, and code:OpDPdyCoarse. |
| Derivative instructions are only available in a fragment shader. |
| |
| [%inline] |
| image::images/vulkantexture2.svg[align="center",title="Implicit Derivatives"] |
| |
| Derivatives are computed as if there is a 2{times}2 neighborhood of |
| fragments for each fragment shader invocation. |
| These neighboring fragments are used to compute derivatives with the |
| assumption that the values of P in the neighborhood are piecewise linear. |
| It is further assumed that the values of P in the neighborhood are locally |
| continuous, therefore derivatives in non-uniform control flow are undefined. |
| |
| [latexmath] |
| +++++++++++++++++++ |
| \begin{aligned} |
| dPdx_{i_1,j_0} & = dPdx_{i_0,j_0} & = P_{i_1,j_0} - P_{i_0,j_0} \\ |
| dPdx_{i_1,j_1} & = dPdx_{i_0,j_1} & = P_{i_1,j_1} - P_{i_0,j_1} \\ |
| \\ |
| dPdy_{i_0,j_1} & = dPdy_{i_0,j_0} & = P_{i_0,j_1} - P_{i_0,j_0} \\ |
| dPdy_{i_1,j_1} & = dPdy_{i_1,j_0} & = P_{i_1,j_1} - P_{i_1,j_0} |
| \end{aligned} |
| +++++++++++++++++++ |
| |
| The code:Fine derivative instructions must: return the values above, for a |
| group of fragments in a 2{times}2 neighborhood. |
| Coarse derivatives may: return only two values. |
| In this case, the values should: be: |
| |
| [latexmath] |
| +++++++++++++++++++ |
| \begin{aligned} |
| dPdx & = |
| \begin{cases} |
| dPdx_{i_0,j_0} & \text{preferred}\\ |
| dPdx_{i_0,j_1} |
| \end{cases} \\ |
| dPdy & = |
| \begin{cases} |
| dPdy_{i_0,j_0} & \text{preferred}\\ |
| dPdy_{i_1,j_0} |
| \end{cases} |
| \end{aligned} |
| +++++++++++++++++++ |
| |
| code:OpDPdx and code:OpDPdy must: return the same result as either |
| code:OpDPdxFine or code:OpDPdxCoarse and either code:OpDPdyFine or |
| code:OpDPdyCoarse, respectively. |
| Implementations must: make the same choice of either coarse or fine for both |
| code:OpDPdx and code:OpDPdy, and implementations should: make the choice |
| that is more efficient to compute. |
| |
| ifdef::VK_VERSION_1_1,VK_KHR_sampler_ycbcr_conversion[] |
| For multi-planar formats, the derivatives are computed based on the plane |
| with the largest dimensions. |
| endif::VK_VERSION_1_1,VK_KHR_sampler_ycbcr_conversion[] |
| |
| |
| [[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 derivative operations |
| above. |
| 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{u}/\partial{x} & = dPdx(u), & \partial{u}/\partial{y} & = dPdy(u), & \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 |
| [eq]#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 [eq]#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, |
| Level-of-Detail Operation>>. |
| |
| For implicit derivative image instructions, the partial derivative values |
| may: be computed by linear approximation using a 2{times}2 neighborhood of |
| shader invocations (known as a _quad_), as described above. |
| If the instruction is in control flow that is not uniform across the quad, |
| then the derivative values and hence the implicit LOD values are undefined. |
| |
| ifdef::VK_EXT_descriptor_indexing[] |
| If the image or sampler object used by an implicit derivative image |
| instruction is not uniform across the quad and |
| <<features-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 |
| <<features-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. |
| |
| For the purposes of implicit derivatives, code:Flat fragment input variables |
| are uniform within a quad. |
| endif::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[] |
| |
| |
| === Scale Factor Operation, Level-of-Detail 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 implicit LOD selected can: be queried using the SPIR-V instruction |
| code:OpImageQueryLod, which gives access to the [eq]#{lambda}#' and |
| [eq]#d~l~# values, defined below. |
| |
| |
| [[textures-scale-factor]] |
| ==== Scale Factor Operation |
| |
| The magnitude of the derivatives are calculated by: |
| |
| :: [eq]#m~ux~ = {vert}{partial}s/{partial}x{vert} {times} w~base~# |
| :: [eq]#m~vx~ = {vert}{partial}t/{partial}x{vert} {times} h~base~# |
| :: [eq]#m~wx~ = {vert}{partial}r/{partial}x{vert} {times} d~base~# |
| |
| :: [eq]#m~uy~ = {vert}{partial}s/{partial}y{vert} {times} w~base~# |
| :: [eq]#m~vy~ = {vert}{partial}t/{partial}y{vert} {times} h~base~# |
| :: [eq]#m~wy~ = {vert}{partial}r/{partial}y{vert} {times} d~base~# |
| |
| |
| where: |
| |
| :: [eq]#{partial}t/{partial}x = {partial}t/{partial}y = 0# (for 1D images) |
| :: [eq]#{partial}r/{partial}x = {partial}r/{partial}y = 0# (for 1D, 2D or |
| Cube images) |
| |
| and |
| |
| :: [eq]#w~base~ = image.w# |
| :: [eq]#h~base~ = image.h# |
| :: [eq]#d~base~ = image.d# |
| |
| (for the pname:baseMipLevel, from the image descriptor). |
| |
| |
| 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: |
| |
| :: [eq]#{rho}~max~ = max({rho}~x~, {rho}~y~)# |
| :: [eq]#{rho}~min~ = min({rho}~x~, {rho}~y~)# |
| |
| The ratio of anisotropy is determined by: |
| |
| :: [eq]#{eta} = min({rho}~max~/{rho}~min~, max~Aniso~)# |
| |
| where: |
| |
| :: [eq]#sampler.max~Aniso~ = pname:maxAnisotropy# (from sampler |
| descriptor) |
| :: [eq]#limits.max~Aniso~ = pname:maxSamplerAnisotropy# (from physical |
| device limits) |
| :: [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]#N# |
| 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: |
| |
| :: [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]] |
| ==== Level-of-Detail 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 <<features-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} |
| d' = level_{base} + \text{clamp}(\lambda, 0, q) |
| \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 |
| |
| :: [eq]#level~base~ = pname:baseMipLevel# |
| :: [eq]#q = pname:levelCount - 1# |
| |
| pname:baseMipLevel and pname:levelCount are taken from the |
| pname:subresourceRange of the image view. |
| |
| 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} & = \lfloor d_{l} \rfloor \\ |
| d_{lo} & = min( d_{hi} + 1, q ) \\ |
| \delta & = d_{l} - d_{hi} |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| [eq]#{delta}# is the fractional value 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 ([eq]#d# or [eq]#d~hi~# |
| and [eq]#d~lo~#) used in <<textures-texel-filtering,filtering>>. |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| u(x,y) & = s(x,y) \times width_{level} \\ |
| v(x,y) & = |
| \begin{cases} |
| 0 & \text{for 1D images} \\ |
| t(x,y) \times height_{level} & \text{otherwise} |
| \end{cases} \\ |
| w(x,y) & = |
| \begin{cases} |
| 0 & \text{for 2D or Cube images} \\ |
| r(x,y) \times depth_{level} & \text{otherwise} |
| \end{cases} \\ |
| \\ |
| a(x,y) & = |
| \begin{cases} |
| a(x,y) & \text{for array images} \\ |
| 0 & \text{otherwise} |
| \end{cases} |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| 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: |
| |
| :: [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 n is assigned the value zero. |
| |
| Nearest filtering (ename:VK_FILTER_NEAREST) computes the integer texel |
| coordinates that the unnormalized coordinates lie within: |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| i &= \lfloor u \rfloor \\ |
| j &= \lfloor v \rfloor \\ |
| k &= \lfloor w \rfloor |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| 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 &= \lfloor u - 0.5 \rfloor \\ |
| i_1 &= i_0 + 1 \\ |
| j_0 &= \lfloor v - 0.5 \rfloor \\ |
| j_1 &= j_0 + 1 \\ |
| k_0 &= \lfloor w - 0.5 \rfloor \\ |
| k_1 &= k_0 + 1 \\ |
| \alpha &= \left(u - 0.5\right) - i_0 \\ |
| \beta &= \left(v - 0.5\right) - j_0 \\ |
| \gamma &= \left(w - 0.5\right) - k_0 |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| ifdef::VK_IMG_filter_cubic[] |
| Cubic filtering (ename:VK_FILTER_CUBIC_IMG) 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~#, |
| as well as weights [eq]#{alpha}# and [eq]#{beta}#. |
| |
| [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 \\ |
| \\ |
| \alpha & = \mathbin{frac} \left ( u - \frac{1}{2} \right ) \\[1em] |
| \beta & = \mathbin{frac} \left ( v - \frac{1}{2} \right ) |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| endif::VK_IMG_filter_cubic[] |
| |
| If the image instruction includes a [eq]#ConstOffset# operand, the constant |
| offsets [eq]#({DeltaUpper}~i~, {DeltaUpper}~j~, {DeltaUpper}~k~)# are added |
| to [eq]#(i,j,k)# components of the integer texel coordinates. |
| |
| |
| [[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)# then any values fetched are |
| ifndef::VK_AMD_shader_image_load_store_lod[undefined.] |
| ifdef::VK_AMD_shader_image_load_store_lod[] |
| undefined, and any writes are discarded. |
| endif::VK_AMD_shader_image_load_store_lod[] |
| |
| |
| [[textures-sample-operations]] |
| == Image Sample Operations |
| |
| |
| [[textures-wrapping-operation]] |
| === Wrapping Operation |
| |
| 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 a 2{times}2 rectangular region of 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: |
| |
| [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} |
| ++++++++++++++++++++++++ |
| |
| 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 Y'C~B~C~R~ conversion>> enabled. |
| endif::VK_VERSION_1_1,VK_KHR_sampler_ycbcr_conversion[] |
| |
| |
| [[textures-texel-filtering]] |
| === Texel Filtering |
| |
| 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. |
| |
| 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} |
| ++++++++++++++++++++++++ |
| |
| Within a mip level, ename:VK_FILTER_LINEAR filtering combines 8 (for 3D), 4 |
| (for 2D or Cube), or 2 (for 1D) texel values, using the weights computed |
| earlier: |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \tau_{3D}[level] & = reduce((1-\alpha)(1-\beta)(1-\gamma),\tau_{i0j0k0}[level], \\ |
| & \, (\alpha)(1-\beta)(1-\gamma),\tau_{i1j0k0}[level], \\ |
| & \, (1-\alpha)(\beta)(1-\gamma),\tau_{i0j1k0}[level], \\ |
| & \, (\alpha)(\beta)(1-\gamma),\tau_{i1j1k0}[level], \\ |
| & \, (1-\alpha)(1-\beta)(\gamma),\tau_{i0j0k1}[level], \\ |
| & \, (\alpha)(1-\beta)(\gamma),\tau_{i1j0k1}[level], \\ |
| & \, (1-\alpha)(\beta)(\gamma),\tau_{i0j1k1}[level], \\ |
| & \, (\alpha)(\beta)(\gamma),\tau_{i1j1k1}[level]) |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \tau_{2D}[level] & = reduce((1-\alpha)(1-\beta),\tau_{i0j0}[level], \\ |
| & \, (\alpha)(1-\beta),\tau_{i1j0}[level], \\ |
| & \, (1-\alpha)(\beta),\tau_{i0j1}[level], \\ |
| & \, (\alpha)(\beta),\tau_{i1j1}[level]) |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \tau_{1D}[level] & = reduce((1-\alpha),\tau_{i0}[level], \\ |
| & \, (\alpha),\tau_{i1}[level]) |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \tau[level] &= |
| \begin{cases} |
| \tau_{3D}[level], & \text{for 3D image} \\ |
| \tau_{2D}[level], & \text{for 2D or Cube image} \\ |
| \tau_{1D}[level], & \text{for 1D image} |
| \end{cases} |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| The function [eq]#reduce()# is defined to operate on pairs of weights and |
| texel values as follows. |
| When using linear or anisotropic filtering, the values of multiple texels |
| are combined using a weighted average to produce a filtered texture value. |
| ifdef::VK_EXT_sampler_filter_minmax[] |
| However, a filtered texture value can: also be produced by computing |
| per-component minimum and maximum values over the set of texels that would |
| normally be averaged. |
| The slink:VkSamplerReductionModeCreateInfoEXT::pname:reductionMode controls |
| the process by which multiple texels are combined to produce a filtered |
| texture value. |
| When set to ename:VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT, a weighted |
| average is computed. |
| If the reduction mode is ename:VK_SAMPLER_REDUCTION_MODE_MIN_EXT or |
| ename:VK_SAMPLER_REDUCTION_MODE_MAX_EXT, [eq]#reduce()# computes a |
| component-wise minimum or maximum, respectively, of the components of the |
| set of provided texels with non-zero weights. |
| endif::VK_EXT_sampler_filter_minmax[] |
| |
| ifdef::VK_IMG_filter_cubic[] |
| Within a mip level, ename:VK_FILTER_CUBIC_IMG filtering computes a weighted |
| average of 16 (for 2D), or 4 (for 1D) texel values, using the weights |
| computed during texel selection. |
| |
| Catmull-Rom Spine interpolation of four points is defined by the equation: |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| cinterp(\tau_0, \tau_1, \tau_2, \tau_3, \omega) = |
| \frac{1}{2} |
| \begin{bmatrix}1 & \omega & \omega^2 & \omega^3 \end{bmatrix} |
| \times |
| \begin{bmatrix} |
| 0 & 2 & 0 & 0 \\ |
| -1 & 0 & 1 & 0 \\ |
| 2 & -5 & 4 & 1 \\ |
| -1 & 3 & -3 & 1 |
| \end{bmatrix} |
| \times |
| \begin{bmatrix} |
| \tau_0 \\ |
| \tau_1 \\ |
| \tau_2 \\ |
| \tau_3 |
| \end{bmatrix} |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| Using the values calculated in texel selection, this equation is applied to |
| the four points in 1D images. |
| For 2D images, the this equation is evaluated first for each row, and the |
| result is then fed back into the equation and interpolated again: |
| |
| :: [eq]#{tau}~1D~[level] = cinterp({tau}~i0~[level], {tau}~i1~[level], |
| {tau}~i2~[level], {tau}~i3~[level], {alpha})# |
| |
| :: [eq]#{tau}~j0~[level] = cinterp({tau}~i0j0~[level], {tau}~i1j0~[level], |
| {tau}~i2j0~[level], {tau}~i3j0~[level], {alpha})# |
| :: [eq]#{tau}~j1~[level] = cinterp({tau}~i0j1~[level], {tau}~i1j1~[level], |
| {tau}~i2j1~[level], {tau}~i3j1~[level], {alpha})# |
| :: [eq]#{tau}~j2~[level] = cinterp({tau}~i0j2~[level], {tau}~i1j2~[level], |
| {tau}~i2j2~[level], {tau}~i3j2~[level], {alpha})# |
| :: [eq]#{tau}~j3~[level] = cinterp({tau}~i0j3~[level], {tau}~i1j3~[level], |
| {tau}~i2j3~[level], {tau}~i3j3~[level], {alpha})# |
| :: [eq]#{tau}~2D~[level] = cinterp({tau}~j0~[level], {tau}~j1~[level], |
| {tau}~j2~[level], {tau}~j3~[level], {beta})# |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \tau[level] &= |
| \begin{cases} |
| \tau_{2D}[level], & \text{for 2D image} \\ |
| \tau_{1D}[level], & \text{for 1D image} |
| \end{cases} |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| endif::VK_IMG_filter_cubic[] |
| |
| Finally, mipmap filtering either selects a value from one mip level or |
| computes a weighted average between neighboring mip levels: |
| |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| \tau &= |
| \begin{cases} |
| \tau[d], & \text{for mip mode BASE or NEAREST} \\ |
| reduce((1-\delta),\tau[d_{hi}],\delta,\tau[d_{lo}]), & \text{for mip mode LINEAR} |
| \end{cases} |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| |
| [[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. |
| |
| 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 be 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 ), |
| \left ( v \left (x-\frac{1}{2}+\frac{i}{N+1} \right ), 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 ), |
| \left ( v \left (x,y-\frac{1}{2}+\frac{i}{N+1} \right ) |
| \right ) |
| \right )}, |
| & \text{when}\ \rho_{y} \geq \rho_{x} |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| ifdef::VK_EXT_sampler_filter_minmax[] |
| |
| When slink:VkSamplerReductionModeCreateInfoEXT::pname:reductionMode is set |
| to ename:VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT, the above summation |
| is used. |
| If the reduction mode is ename:VK_SAMPLER_REDUCTION_MODE_MIN_EXT or |
| ename:VK_SAMPLER_REDUCTION_MODE_MAX_EXT, then the value is instead computed |
| as [eq]#\tau_{2Daniso} = reduce(\tau_1, ..., \tau_N)#, combining all texel |
| values with non-zero weights. |
| |
| endif::VK_EXT_sampler_filter_minmax[] |
| |
| |
| [[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*code:Dref instructions. |
| * All Texel output operations: Performed by code:OpImageWrite. |
| * Projection: Performed by all code:OpImage*code:Proj instructions. |
| * Derivative Image Operations, Cube Map Operations, Scale Factor |
| Operation, Level-of-Detail 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*code:Gather instructions. |
| * Texel Gathering: Performed by code:OpImage*code:Gather instructions. |
| * Texel Filtering: Performed by all code:OpImageSample* and |
| code:OpImageSparseSample* instructions. |
| * Sparse Residency: Performed by all code:OpImageSparse* instructions. |