| // Copyright 2018-2023 The Khronos Group Inc. |
| // |
| // SPDX-License-Identifier: CC-BY-4.0 |
| |
| [[fragmentdensitymapops]] |
| = Fragment Density Map Operations |
| |
| |
| == Fragment Density Map Operations Overview |
| |
| When a fragment is generated in a render pass that has a fragment density |
| map attachment, its area is determined by the properties of the local |
| framebuffer region that the fragment occupies. |
| The framebuffer is divided into a uniform grid of these local regions, and |
| their fragment area property is derived from the density map with the |
| following operations: |
| |
| * <<fragmentdensitymap-fetch-density-value,Fetch density value>> |
| ** <<fragmentdensitymap-component-swizzle,Component swizzle>> |
| ** <<fragmentdensitymap-component-mapping,Component mapping>> |
| * <<fragmentdensitymap-conversion-to-fragment-area,Fragment area |
| conversion>> |
| ** <<fragmentdensitymap-fragment-area-filter,Fragment area filter>> |
| ** <<fragmentdensitymap-fragment-area-clamp,Fragment area clamp>> |
| |
| |
| [[fragmentdensitymap-fetch-density-value]] |
| == Fetch Density Value |
| |
| ifndef::VK_QCOM_fragment_density_map_offset[] |
| Each local framebuffer region at center coordinate [eq]#(x,y)# fetches a |
| texel from the fragment density map at integer coordinates: |
| |
| {empty}:: latexmath:[i = |
| \left\lfloor{\frac{x}{fragmentDensityTexelSize_{width}}}\right\rfloor] |
| {empty}:: latexmath:[j = |
| \left\lfloor{\frac{y}{fragmentDensityTexelSize_{height}}}\right\rfloor] |
| endif::VK_QCOM_fragment_density_map_offset[] |
| |
| ifdef::VK_QCOM_fragment_density_map_offset[] |
| Each local framebuffer region at center coordinate [eq]#(x,y)# fetches a |
| texel from the fragment density map. |
| |
| First, the local framebuffer region center coordinate [eq]#(x,y)# is offset |
| by the value specified in |
| slink:VkSubpassFragmentDensityMapOffsetEndInfoQCOM. |
| If no offset is specified, then the default offset [eq]#(0,0)# is used. |
| The offsetted coordinate [eq]#(x',y')# is computed as follows: |
| |
| [latexmath] |
| [latexmath] |
| ++++++++++++++++++++++++ |
| \begin{aligned} |
| x' &= \mathbin{clamp}(x + pFragmentDensityOffsets[layer]_{x}, 0, framebuffer_{width} - 1) \\ |
| y' &= \mathbin{clamp}(y + pFragmentDensityOffsets[layer]_{y}, 0, framebuffer_{height} - 1) \\ |
| \end{aligned} |
| ++++++++++++++++++++++++ |
| |
| The offsetted coordinate [eq]#(x',y')# fetches a texel from the fragment |
| density map at integer coordinates: |
| |
| {empty}:: latexmath:[i = |
| \left\lfloor{\frac{x'}{fragmentDensityTexelSize_{width}}}\right\rfloor] |
| {empty}:: latexmath:[j = |
| \left\lfloor{\frac{y'}{fragmentDensityTexelSize_{height}}}\right\rfloor] |
| endif::VK_QCOM_fragment_density_map_offset[] |
| |
| Where the size of each region in the framebuffer is: |
| |
| {empty}:: latexmath:[fragmentDensityTexelSize'_{width} = |
| {2^{\lceil{\log_2(\frac{framebuffer_{width}}{fragmentDensityMap_{width}})}\rceil}}] |
| {empty}:: latexmath:[fragmentDensityTexelSize'_{height} = |
| {2^{\lceil{\log_2(\frac{framebuffer_{height}}{fragmentDensityMap_{height}})}\rceil}}] |
| |
| This region is subject to the limits in |
| sname:VkPhysicalDeviceFragmentDensityMapPropertiesEXT and therefore the |
| final region size is clamped: |
| |
| {empty}:: latexmath:[fragmentDensityTexelSize_{width} = |
| \mathbin{clamp}(fragmentDensityTexelSize'_{width},minFragmentDensityTexelSize_{width},maxFragmentDensityTexelSize_{width})] |
| {empty}:: latexmath:[fragmentDensityTexelSize_{height} = |
| \mathbin{clamp}(fragmentDensityTexelSize'_{height},minFragmentDensityTexelSize_{height},maxFragmentDensityTexelSize_{height})] |
| |
| When multiview is enabled for the render pass and the fragment density map |
| attachment view was created with pname:layerCount greater than `1`, the |
| layer used for offsets and for fetching from the fragment density map is: |
| |
| {empty}:: latexmath:[layer = baseArrayLayer + ViewIndex] |
| |
| Otherwise: |
| |
| {empty}:: latexmath:[layer = baseArrayLayer] |
| |
| The texel fetched from the density map at [eq]#(i,j,layer)# is next |
| converted to density with the following operations. |
| |
| |
| [[fragmentdensitymap-component-swizzle]] |
| === Component Swizzle |
| |
| The pname:components member of slink:VkImageViewCreateInfo is applied to the |
| fetched texel as defined in <<textures-component-swizzle,Image component |
| swizzle>>. |
| |
| |
| [[fragmentdensitymap-component-mapping]] |
| === Component Mapping |
| |
| The swizzled texel's components are mapped to a density value: |
| |
| {empty}:: latexmath:[densityValue_{xy} = (C'_{r},C'_{g})] |
| |
| |
| [[fragmentdensitymap-conversion-to-fragment-area]] |
| == Fragment Area Conversion |
| |
| Fragment area for the framebuffer region is undefined: if the density |
| fetched is not a normalized floating-point value greater than `0.0`. |
| Otherwise, the fetched fragment area for that region is derived as: |
| |
| {empty}:: latexmath:[fragmentArea_{wh} = \frac{1.0}{densityValue_{xy}}] |
| |
| |
| [[fragmentdensitymap-fragment-area-filter]] |
| === Fragment Area Filter |
| |
| Optionally, the implementation may: fetch additional density map texels in |
| an implementation defined window around [eq]#(i,j)#. |
| The texels follow the standard conversion steps up to and including |
| <<fragmentdensitymap-conversion-to-fragment-area,fragment area conversion>>. |
| |
| A single fetched fragment area for the framebuffer region is chosen by the |
| implementation and must: have an area between the _min_ and _max_ areas of |
| the fetched set. |
| |
| |
| [[fragmentdensitymap-fragment-area-clamp]] |
| === Fragment Area Clamp |
| |
| The implementation may: clamp the fetched fragment area to one that it |
| supports. |
| The clamped fragment area must: have a size less than or equal to the |
| original fetched value. |
| Implementations may: vary the supported set of fragment areas per |
| framebuffer region. |
| Fragment area [eq]#(1,1)# must: always be in the supported set. |
| |
| [NOTE] |
| .Note |
| ==== |
| For example, if the fetched fragment area is [eq]#(1,4)# but the |
| implementation only supports areas of [eq]#{(1,1),(2,2)}#, it could choose |
| to clamp the area to [eq]#(2,2)# since it has the same size as [eq]#(1,4)#. |
| While this would produce fragments that have lower quality strictly in the |
| x-axis, the overall density is maintained. |
| ==== |
| |
| The clamped fragment area is assigned to the corresponding framebuffer |
| region. |