protonscr

vkd3d-proton calling vkGetDescriptorEXT() with range of half-a-pixel

vkd3dclosed
HansKristian-Work/vkd3d-proton#2968 · opened 2026-04-27 by pzanoni-intel · updated 2026-04-29 · 5 comments · github
Ppzanoni-intel 2026-04-27 github

Hi

When running The Last Of Us Part II Remastered with the Mesa Anv driver in debug mode, we're hitting an assertion regarding num_elements because vkGetDescriptorEXT() is passing a range of 1 for an R16 descriptor:

(gdb) bt
#0  gdb_break_here () at ../../src/intel/isl/isl_surface_state.c:1013
#1  0x00007f713e257ba1 in isl_gfx30_buffer_fill_state_s (dev=0x55556f63daa0, state=0x1dcd4840, info=0x1000ffa50) at ../../src/intel/isl/isl_surface_state.c:1025
#2  0x00007f713c261be2 in anv_fill_buffer_surface_state (device=0x55556f63c2a0, surface_state_ptr=0x1dcd4840, format=ISL_FORMAT_R16_UINT, swizzle=..., usage=8, address=..., range=0, stride=2) at ../../src/intel/vulkan/anv_buffer.c:334
#3  0x00007f713c271f30 in anv_GetDescriptorEXT (_device=0x55556f63c2a0, pDescriptorInfo=0x10d180, dataSize=64, pDescriptor=0x1dcd4840) at ../../src/intel/vulkan/anv_descriptor_set.c:2848
#4  0x00007f714a16d506 in __wine_unix_call_dispatcher () from target:/mnt/d2/home/pzanoni/steam/debian-installation/steamapps/common/Proton Hotfix/files/lib/wine/x86_64-unix/ntdll.so
#5  0x00007f714a16b37b in server_init_process_done () from target:/mnt/d2/home/pzanoni/steam/debian-installation/steamapps/common/Proton Hotfix/files/lib/wine/x86_64-unix/ntdll.so
#6  0x00007f714be1217a in ?? ()
#7  0x0000000000000000 in ?? ()
(gdb) frame 3
#3  0x00007f713c271f30 in anv_GetDescriptorEXT (_device=0x55556f63c2a0, pDescriptorInfo=0x10d180, dataSize=64, pDescriptor=0x1dcd4840) at ../../src/intel/vulkan/anv_descriptor_set.c:2848
2848	         anv_fill_buffer_surface_state(device, pDescriptor,
(gdb) print *pDescriptorInfo
$4 = {
  sType = VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT,
  pNext = 0x0,
  type = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
  data = {
    pSampler = 0x10d1a0,
    pCombinedImageSampler = 0x10d1a0,
    pInputAttachmentImage = 0x10d1a0,
    pSampledImage = 0x10d1a0,
    pStorageImage = 0x10d1a0,
    pUniformTexelBuffer = 0x10d1a0,
    pStorageTexelBuffer = 0x10d1a0,
    pUniformBuffer = 0x10d1a0,
    pStorageBuffer = 0x10d1a0,
    accelerationStructure = 1102240
  }
}
(gdb) print *pDescriptorInfo->data.pUniformTexelBuffer
$5 = {
  sType = VK_STRUCTURE_TYPE_DESCRIPTOR_ADDRESS_INFO_EXT,
  pNext = 0x0,
  address = 18384289792,
  range = 1,
  format = VK_FORMAT_R16_UINT
}

It seems that if the app passed range = 0, it would be violating VUID-VkDescriptorAddressInfoEXT-range-08940, but I can't find text that says "half a pixel" is invalid. Anv rounds range down to "whole pixels", which transforms it into 0, so we hit the assertion in the ISL code.

I'm not sure how much this is on purpose, or expected, so, before removing the assertion in Anv, I'd like to have your assessment here. Is this a vkd3d bug? Is this a Game bug?

This may be related somehow to https://github.com/HansKristian-Work/vkd3d-proton/issues/2071 ?

Thanks a lot!

Ddoitsujin maintainer 2026-04-28 github

Does https://github.com/doitsujin/vkd3d/tree/srv-frog work around the problem?

Note that this isn't a proper fix, but more of quick attempt to figure out what the issue is. I don't have the game installed to check locally at the moment.

HHansKristian-Work maintainer 2026-04-28 github

That is rather surprising since 8-bit structured buffer does not exist in D3D12, but could be game bug ...

Ppzanoni-intel 2026-04-28 github

Does https://github.com/doitsujin/vkd3d/tree/srv-frog work around the problem?

Note that this isn't a proper fix, but more of quick attempt to figure out what the issue is. I don't have the game installed to check locally at the moment.

Yes, it does. The game launches and I can spot 2 frogs in the logs.

$ cat steam-2531310.log  | grep frog
3090271.496:0150:0154:err:vkd3d-proton:vkd3d_structured_srv_to_texel_buffer_dxgi_format: frog
3090271.496:0150:0154:err:vkd3d-proton:vkd3d_structured_uav_to_texel_buffer_dxgi_format: frog

I'll be happy to test more stuff or provide more data if you need.

Thanks!

Mmengchenli1980 2026-04-29 github

I have read through the previous comments and the proposed fix. Just one additional note.The crash is triggered along the following path:

d3d12_device_CreateShaderResourceView_embedded → d3d12_desc_create_srv_embedded → vkd3d_create_buffer_srv_embedded.

Under normal conditions, when the game passes a valid VK_FORMAT_R16_UINT, the function vkd3d_get_metadata_buffer_view_for_resource correctly computes view->range = 2. Everything works as expected. However, if the game passes a specific set of parameters — likely a game-side bug — the following edge case occurs:
desc->Format = DXGI_FORMAT_UNKNOWN
desc->Buffer.NumElements = 1
desc->Buffer.StructureByteStride = 1
desc->Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE

  1. Because desc->Format == DXGI_FORMAT_UNKNOWN and desc->Buffer.StructureByteStride == 1, the function vkd3d_get_metadata_buffer_view_for_resource returns view->range = 1.
  2. The code then reaches the format fallback logic:
    if (desc->Buffer.Flags & D3D12_BUFFER_SRV_FLAG_RAW)
    {
    addr_info.format = VK_FORMAT_R32_UINT;
    }
    else
    {
    addr_info.format = vkd3d_internal_get_vk_format(device,
    vkd3d_structured_srv_to_texel_buffer_dxgi_format(desc->Buffer.StructureByteStride));
    }
    Since desc->Buffer.StructureByteStride == 1 does not match any condition in vkd3d_structured_srv_to_texel_buffer_dxgi_format, it falls through to the default return value of DXGI_FORMAT_R16_UINT.
  3. The subsequent call to vkGetDescriptorEXT passes range = 1 and format = VK_FORMAT_R16_UINT. Inside the Mesa ANV driver, the call chain anv_GetDescriptorEXT → anv_fill_buffer_surface_state → isl_gfx30_buffer_fill_state_s computes:

isl_genX(buffer_fill_state_s)(const struct isl_device *dev, void *state,
const struct isl_buffer_fill_state_info *restrict info)
{
uint64_t buffer_size = info->size_B;
.......
uint64_t num_elements = buffer_size / info->stride_B;
assert(num_elements > 0);
s.Height = ((num_elements - 1) >> 7) & 0x3fff;
s.Width = (num_elements - 1) & 0x7f;
s.Depth = ((num_elements - 1) >> 21) & 0x7ff;
}
In a Mesa debug build, assert(num_elements > 0) fires and terminates the game application. In a release build, the assertion is compiled out. The code proceeds with num_elements == 0, which produces incorrect values for Height, Width, and Depth written to the hardware surface state registers. This can lead to rendering corruption, screen artifacts, or other subtle GPU misbehaviour. As the proposed fix suggests, this is about handling the edge case of range = 1.

Ppzanoni-intel 2026-04-29 github

I tested the updated tree and it seems to work for me. That was fast! Thanks a lot, everybody!

Proton versions

Upstream links