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:

Fetch Density Value

Each local framebuffer region at center coordinate (x,y) fetches a texel from the fragment density map.

First, the local framebuffer region center coordinate (x,y) is offset by the value specified in VkSubpassFragmentDensityMapOffsetEndInfoQCOM. If no offset is specified, then the default offset (0,0) is used. The offsetted coordinate (x',y') is computed as follows:

x=clamp(x+pFragmentDensityOffsets\[layer]x,0,framebufferwidth1) y=clamp(y+pFragmentDensityOffsets\[layer]y,0,framebufferheight1) \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 (x',y') fetches a texel from the fragment density map at integer coordinates:

  • i=xfragmentDensityTexelSize_widthi = \left\lfloor{\frac{x'}{fragmentDensityTexelSize\_{width}}}\right\rfloor
  • j=yfragmentDensityTexelSize_heightj = \left\lfloor{\frac{y'}{fragmentDensityTexelSize\_{height}}}\right\rfloor

Where the size of each region in the framebuffer is:

  • fragmentDensityTexelSize_width=2log_2(framebuffer_widthfragmentDensityMap_width)fragmentDensityTexelSize'\_{width} = {2^{\lceil{\log\_2(\frac{framebuffer\_{width}}{fragmentDensityMap\_{width}})}\rceil}}
  • fragmentDensityTexelSize_height=2log_2(framebuffer_heightfragmentDensityMap_height)fragmentDensityTexelSize'\_{height} = {2^{\lceil{\log\_2(\frac{framebuffer\_{height}}{fragmentDensityMap\_{height}})}\rceil}}

This region is subject to the limits in VkPhysicalDeviceFragmentDensityMapPropertiesEXT and therefore the final region size is clamped:

  • fragmentDensityTexelSize_width=clamp(fragmentDensityTexelSize_width,minFragmentDensityTexelSize_width,maxFragmentDensityTexelSize_width)fragmentDensityTexelSize\_{width} = \mathbin{clamp}(fragmentDensityTexelSize'\_{width},minFragmentDensityTexelSize\_{width},maxFragmentDensityTexelSize\_{width})
  • fragmentDensityTexelSize_height=clamp(fragmentDensityTexelSize_height,minFragmentDensityTexelSize_height,maxFragmentDensityTexelSize_height)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 layerCount greater than 1, the layer used for offsets and for fetching from the fragment density map is:

  • layer=baseArrayLayer+ViewIndexlayer = baseArrayLayer + ViewIndex

Otherwise:

  • layer=baseArrayLayerlayer = baseArrayLayer

The texel fetched from the density map at (i,j,layer) is next converted to density with the following operations.

Component Swizzle

The components member of VkImageViewCreateInfo is applied to the fetched texel as defined in Image component swizzle.

Component Mapping

The swizzled texel’s components are mapped to a density value:

  • densityValue_xy=(C_r,C_g)densityValue\_{xy} = (C'\_{r},C'\_{g})

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:

  • fragmentArea_wh=1.0densityValue_xyfragmentArea\_{wh} = \frac{1.0}{densityValue\_{xy}}

Fragment Area Filter

Optionally, the implementation may fetch additional density map texels in an implementation defined window around (i,j). The texels follow the standard conversion steps up to and including 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.

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 (1,1) must always be in the supported set.

For example, if the fetched fragment area is (1,4) but the implementation only supports areas of {(1,1),(2,2)}, it could choose to clamp the area to (2,2) since it has the same size as (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.