protonscr

Teardown: ExecuteIndirect draws silently dropped on Turnip — command signature is still created when DGC is unavailable (regression from 2.14.1)

vkd3dclosed
HansKristian-Work/vkd3d-proton#3246 · opened 2026-08-29 by OnickerForever · updated 2026-08-31 · 4 comments · github
OOnickerForever 2026-08-29 github

Teardown renders with large parts of the world missing on 3.x: buildings don't draw at all, and surfaces that should be opaque show whatever is behind them. Same game, same GPU, same driver renders correctly on 2.14.1.

Turnip doesn't implement VK_EXT_device_generated_commands, so the command signatures this game creates that change vertex/index buffer views and root CBVs between commands can't be backed by a state template. On 2.14.1 those CreateCommandSignature calls simply failed:

if ((pipeline_type == VKD3D_PIPELINE_TYPE_GRAPHICS || pipeline_type == VKD3D_PIPELINE_TYPE_MESH_GRAPHICS) &&
        !device->device_info.device_generated_commands_features_nv.deviceGeneratedCommands &&
        !device->device_info.device_generated_commands_features_ext.deviceGeneratedCommands)
{
    FIXME("Device generated commands is not supported by implementation.\n");
    hr = E_NOTIMPL;
    goto err;
}

Since 3.0 the same path returns success instead (libs/vkd3d/command.c, d3d12_command_signature_create, unchanged in master):

if (!device->device_info.device_generated_commands_features.deviceGeneratedCommands)
{
    FIXME("Device generated commands is not supported by implementation.\n");
    object->requires_state_template = false;
    goto out;
}

So the application gets S_OK and a signature that has quietly dropped the state template it needs. It then calls ExecuteIndirect, requires_state_template is false, the plain path runs, the per-command binding changes are ignored, and those draws produce nothing. Nothing reports an error — the log only contains the FIXME, 11 times in my case.

Teardown handles the old behaviour correctly: it checks the returned signature for NULL and falls back to issuing those draws from the CPU, which is why 2.14.1 looks right.

I patched the DLL to restore the old behaviour (set hr to a failure code and jump to err: instead of out:) and the game renders correctly again, while still using indirect draws for the signatures that don't need a state template.

The ray tracing branch a few lines below does the same thing (requires_state_template = false; goto out;), so it probably has the same problem.

Software information

Teardown 2.1.0, 640x480, default graphics settings.

System information

  • GPU: Adreno 610 (Turnip)
  • Driver: Turnip, mesa-git nightly 26.3.0
  • Wine version: Winlator (bundled Wine)
  • VKD3D-Proton version: 3.1.0, build c9c6bf2e9c18252 (ARM64EC build). 2.14.1 on the same setup is fine.

Not Proton — this is Winlator on Android, so vkd3d-proton runs under Wine on aarch64. The command.c in the build I used is byte-identical to current master, and v3.0.1 has the same code, so the analysis above isn't specific to that build.

Log files

This isn't Proton, so there's no steam-xxxxx.log. The vkd3d log for the run with the missing geometry (stock game binary, unpatched vkd3d) is 106 lines and contains nothing but the usual startup chatter plus this:

info:vkd3d_config_flags_init_once: VKD3D_CONFIG='force_raw_va_cbv'.
info:vkd3d_get_vk_version: vkd3d-proton - applicationVersion: 3.1.0.
info:vkd3d_instance_init: vkd3d-proton - build: c9c6bf2e9c18252.
info:vkd3d_init_device_caps: Not all relevant pipeline stages are supported by EXT_dgc. Skipping.
...
fixme:d3d12_command_signature_create: Device generated commands is not supported by implementation.
   (x11)

11 FIXMEs and no errors or warnings anywhere — that's the point, the failure is completely silent. I can attach the full file if it's useful. force_raw_va_cbv is unrelated, it's needed on this GPU because maxBoundDescriptorSets is 4.

OOnickerForever 2026-08-29 github
Image Image
HHansKristian-Work maintainer 2026-08-29 github

Teardown handles the old behaviour correctly: it checks the returned signature for NULL and falls back to issuing those draws from the CPU, which is why 2.14.1 looks right.

Seems more like a workaround than anything, but sure. If actively failing the call fixes Teardown we can add a config option and app-opt. Is that something you can do on your own?

OOnickerForever 2026-08-29 github

Yeah, it's a workaround — the real fix is Turnip implementing DGC. The MR for that (mesa!31388) is a stale draft from 2024 and only enables the extension on a750+ (a7xx.load_shader_consts_via_preamble), so nothing is coming for a6xx soon.

Failing the call is enough, I checked rather than guessed: I patched the DLL locally to set an error and jump to err: instead of falling through to out:, and the game renders correctly again. It still uses ExecuteIndirect for the signatures that don't need a state template, so this isn't just "indirect draws off".

Happy to do the PR. Shape I had in mind: a config flag checked in that branch plus an application_override entry for teardown.exe.

Two things I'd rather you decide before I write it:

  • The ray tracing branch right below does the same requires_state_template = false; goto out;. Should the flag cover it too, or leave it alone?
  • Name for the flag — I've been calling it fail_unsupported_state_template, but I have no attachment to it.
HHansKristian-Work maintainer 2026-08-29 github

flag should cover RT too, noone uses DGC RT so I don't really care. Sure, fail_unsupported_state_template is fine.