protonscr

test_sampler_rounding fails on Turnip in gather, linear filter subtests

vkd3dclosed
HansKristian-Work/vkd3d-proton#2383 · opened 2025-03-09 by zdobersek · updated 2025-04-08 · 4 comments · github
Zzdobersek 2025-03-09 github

Software information

The test_sampler_rounding unit test has a few subtests that fail on Turnip. The tests are run on a 2x1 texture where the left pixel is transparent and the right pixel is opaque.

Gather

Two subtests (indices 2 and 3) covering gather operation fail because of how the selected texels are determined. With unnormalized texture coordinates, my understanding is that D3D will subtract 0.5f before converting those coordinates to 16.8 fixed-point values. After the conversion the integer part will be used as the base texel position in a given coordinate axis.

Vulkan's texel selection (16.6.1) for gather operation doesn't require conversion to fixed-point. Turnip behaves accordingly.

The two subtests essentially check when the gathered texels will shift from including both left and right pixels to including only the right pixel. For D3D, because of the rounding-to-nearest behavior during conversion to 16.8 fixed-point, this would happen already for coordinate values that are close but still less than 1.5. On Turnip, this will happen when the unnormalized coordinate is 1.5 or larger, which matches the existing use_warp_device codepath.

Linear filtering

This subtest (index 1) fails on Turnip because of Adreno's sampler behavior when performing linear filtering (16.8.3). The fraction parts of the unnormalized and shift-adjusted values are used as weights by which each texel is multiplied.

Examining the output values with Turnip, Adreno sampler does seem to use conversion of weight values to 16.8 fixed-point in order to compute the linear sample value, but unlike D3D's float-to-fixed-point conversion it floors the value when converting it to integer, instead of rounding it. Vulkan doesn't require rounding (3.10.2).

System information

  • GPU: Adreno A750
  • Driver: Mesa Turnip, main branch
  • Wine version: wine-9.21 (Staging)
  • VKD3D-Proton version: master branch, tag v2.14.1
HHansKristian-Work maintainer 2025-03-10 github

There is content that relies on gather to have RTE semantics similar to LINEAR filtering, fwiw, and failing that leads to broken graphics. AMD's CACAO demo is a good example of this. The specification also states that GATHER picks the same samples that would be selected from a LINEAR filter operation.

This effect is observable on a GPU which supports sparse residency, since you can construct a test that requires the rounding for LINEAR and GATHER to work the same way when querying residency status on the edge of a page.

I think this can be understood to mean that GATHER should round, similar to LINEAR. NVIDIA has this behavior by default, and on RADV we modify the SGPR to force sub-texel rounding for GATHER.

If Turnip cannot pick the rounding on instruction time, the suggestion I think is to just force D3D-style rounding on samplers in DXVK/vkd3d-proton mode. If that cannot be done, we'll need an extension to control this behavior.

Zzdobersek 2025-03-11 github

Adreno supports toggling between these two types of behavior through a register flag.

Turnip change is in Mesa's MR33987. Only change needed in vkd3d would be making PointSamplingAddressesNeverRoundUp also true for Turnip.

HHansKristian-Work maintainer 2025-03-11 github

I think vkd3d-proton is reporting the correct property as-is.

Zzdobersek 2025-04-07 github

Mesa change landed. Since Turnip now uses round-to-even when calculating unnormalized texture coordinates, my understanding is that PointSamplingAddressesNeverRoundUp should not be exposed for Turnip. That change is in PR https://github.com/HansKristian-Work/vkd3d-proton/pull/2431.