1// Copyright 2018-2023 The Khronos Group Inc. 2// 3// SPDX-License-Identifier: CC-BY-4.0 4 5[[fragmentdensitymapops]] 6= Fragment Density Map Operations 7 8 9== Fragment Density Map Operations Overview 10 11When a fragment is generated in a render pass that has a fragment density 12map attachment, its area is determined by the properties of the local 13framebuffer region that the fragment occupies. 14The framebuffer is divided into a uniform grid of these local regions, and 15their fragment area property is derived from the density map with the 16following operations: 17 18 * <<fragmentdensitymap-fetch-density-value,Fetch density value>> 19 ** <<fragmentdensitymap-component-swizzle,Component swizzle>> 20 ** <<fragmentdensitymap-component-mapping,Component mapping>> 21 * <<fragmentdensitymap-conversion-to-fragment-area,Fragment area 22 conversion>> 23 ** <<fragmentdensitymap-fragment-area-filter,Fragment area filter>> 24 ** <<fragmentdensitymap-fragment-area-clamp,Fragment area clamp>> 25 26 27[[fragmentdensitymap-fetch-density-value]] 28== Fetch Density Value 29 30ifndef::VK_QCOM_fragment_density_map_offset[] 31Each local framebuffer region at center coordinate [eq]#(x,y)# fetches a 32texel from the fragment density map at integer coordinates: 33 34 {empty}:: latexmath:[i = 35 \left\lfloor{\frac{x}{fragmentDensityTexelSize_{width}}}\right\rfloor] 36 {empty}:: latexmath:[j = 37 \left\lfloor{\frac{y}{fragmentDensityTexelSize_{height}}}\right\rfloor] 38endif::VK_QCOM_fragment_density_map_offset[] 39 40ifdef::VK_QCOM_fragment_density_map_offset[] 41Each local framebuffer region at center coordinate [eq]#(x,y)# fetches a 42texel from the fragment density map. 43 44First, the local framebuffer region center coordinate [eq]#(x,y)# is offset 45by the value specified in 46slink:VkSubpassFragmentDensityMapOffsetEndInfoQCOM. 47If no offset is specified, then the default offset [eq]#(0,0)# is used. 48The offsetted coordinate [eq]#(x',y')# is computed as follows: 49 50[latexmath] 51[latexmath] 52++++++++++++++++++++++++ 53\begin{aligned} 54x' &= \mathbin{clamp}(x + pFragmentDensityOffsets[layer]_{x}, 0, framebuffer_{width} - 1) \\ 55y' &= \mathbin{clamp}(y + pFragmentDensityOffsets[layer]_{y}, 0, framebuffer_{height} - 1) \\ 56\end{aligned} 57++++++++++++++++++++++++ 58 59The offsetted coordinate [eq]#(x',y')# fetches a texel from the fragment 60density map at integer coordinates: 61 62 {empty}:: latexmath:[i = 63 \left\lfloor{\frac{x'}{fragmentDensityTexelSize_{width}}}\right\rfloor] 64 {empty}:: latexmath:[j = 65 \left\lfloor{\frac{y'}{fragmentDensityTexelSize_{height}}}\right\rfloor] 66endif::VK_QCOM_fragment_density_map_offset[] 67 68Where the size of each region in the framebuffer is: 69 70 {empty}:: latexmath:[fragmentDensityTexelSize'_{width} = 71 {2^{\lceil{\log_2(\frac{framebuffer_{width}}{fragmentDensityMap_{width}})}\rceil}}] 72 {empty}:: latexmath:[fragmentDensityTexelSize'_{height} = 73 {2^{\lceil{\log_2(\frac{framebuffer_{height}}{fragmentDensityMap_{height}})}\rceil}}] 74 75This region is subject to the limits in 76sname:VkPhysicalDeviceFragmentDensityMapPropertiesEXT and therefore the 77final region size is clamped: 78 79 {empty}:: latexmath:[fragmentDensityTexelSize_{width} = 80 \mathbin{clamp}(fragmentDensityTexelSize'_{width},minFragmentDensityTexelSize_{width},maxFragmentDensityTexelSize_{width})] 81 {empty}:: latexmath:[fragmentDensityTexelSize_{height} = 82 \mathbin{clamp}(fragmentDensityTexelSize'_{height},minFragmentDensityTexelSize_{height},maxFragmentDensityTexelSize_{height})] 83 84When multiview is enabled for the render pass and the fragment density map 85attachment view was created with pname:layerCount greater than `1`, the 86layer used for offsets and for fetching from the fragment density map is: 87 88 {empty}:: latexmath:[layer = baseArrayLayer + ViewIndex] 89 90Otherwise: 91 92 {empty}:: latexmath:[layer = baseArrayLayer] 93 94The texel fetched from the density map at [eq]#(i,j,layer)# is next 95converted to density with the following operations. 96 97 98[[fragmentdensitymap-component-swizzle]] 99=== Component Swizzle 100 101The pname:components member of slink:VkImageViewCreateInfo is applied to the 102fetched texel as defined in <<textures-component-swizzle,Image component 103swizzle>>. 104 105 106[[fragmentdensitymap-component-mapping]] 107=== Component Mapping 108 109The swizzled texel's components are mapped to a density value: 110 111 {empty}:: latexmath:[densityValue_{xy} = (C'_{r},C'_{g})] 112 113 114[[fragmentdensitymap-conversion-to-fragment-area]] 115== Fragment Area Conversion 116 117Fragment area for the framebuffer region is undefined: if the density 118fetched is not a normalized floating-point value greater than `0.0`. 119Otherwise, the fetched fragment area for that region is derived as: 120 121 {empty}:: latexmath:[fragmentArea_{wh} = \frac{1.0}{densityValue_{xy}}] 122 123 124[[fragmentdensitymap-fragment-area-filter]] 125=== Fragment Area Filter 126 127Optionally, the implementation may: fetch additional density map texels in 128an implementation defined window around [eq]#(i,j)#. 129The texels follow the standard conversion steps up to and including 130<<fragmentdensitymap-conversion-to-fragment-area,fragment area conversion>>. 131 132A single fetched fragment area for the framebuffer region is chosen by the 133implementation and must: have an area between the _min_ and _max_ areas of 134the fetched set. 135 136 137[[fragmentdensitymap-fragment-area-clamp]] 138=== Fragment Area Clamp 139 140The implementation may: clamp the fetched fragment area to one that it 141supports. 142The clamped fragment area must: have a size less than or equal to the 143original fetched value. 144Implementations may: vary the supported set of fragment areas per 145framebuffer region. 146Fragment area [eq]#(1,1)# must: always be in the supported set. 147 148[NOTE] 149.Note 150==== 151For example, if the fetched fragment area is [eq]#(1,4)# but the 152implementation only supports areas of [eq]#{(1,1),(2,2)}#, it could choose 153to clamp the area to [eq]#(2,2)# since it has the same size as [eq]#(1,4)#. 154While this would produce fragments that have lower quality strictly in the 155x-axis, the overall density is maintained. 156==== 157 158The clamped fragment area is assigned to the corresponding framebuffer 159region. 160