Files
NX2navi/runtime/shaders/meshfb_clamp.comp
chrg6 edd5d04e8c Cut a mesh fallback draw's workgroup count that the GPU wrote to what the fallback's buffers hold before a dispatch reads it.
The record's copies put the count the game's culling pass wrote into the first dispatch and, without a task stage, into the draw's instances as it was. A garbage count launched up to millions of workgroups that write nothing and instances that draw nothing, enough to keep the GPU past the driver's timeout; with the fallback now the default on AMD's driver for RDNA 1 and 2, such a count would have moved a hang there instead of removing it. A single-thread compute pass (shaders/meshfb_clamp.comp) cuts the count to the buffers' room, which changes nothing that is drawn; the report word keeps the count asked for, so record_check still logs a mesh-only draw that asked for more than the buffers hold. On for every device that uses the fallback: one dispatch and one barrier per indirect fallback draw.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-13 12:54:24 -05:00

30 lines
1.6 KiB
Plaintext

#version 450
// The mesh fallback's pass between a draw's record and its first dispatch, for a draw whose workgroup count the GPU
// wrote (vk_mesh_fb.c vk_meshfb_clamp, vk_exec_draw.c mfb_draw). The record's copies put that count into the first
// dispatch and, without a task stage, into the draw's instances as it is; a garbage count (the game's culling pass
// reading memory nothing wrote) would launch up to millions of workgroups that write nothing and instances that draw
// nothing, past the buffers' end, and keep the GPU busy past the driver's timeout. The count is cut to what the
// buffers hold, which changes nothing that is drawn; the record's report word keeps the count asked for, so the log
// names such a draw (vk_mesh_fb.c record_check).
layout(local_size_x = 1) in;
layout(push_constant) uniform Params {
uint rec; // the record's first word in the record buffer
uint task; // 1: the count is the task dispatch's (word 0); 0: the mesh dispatch's and the draw's instances (4, 9)
uint room; // workgroups the buffers hold, at most what one dispatch may have
} pc;
// The record (meshfb_scan.comp): words 0-2 the task dispatch, 4-6 the mesh dispatch, 8-11 the draw (vertices,
// instances, first vertex, first instance), 12 the mesh workgroups asked for, 13 the task workgroups.
layout(set = 0, binding = 0) buffer Rec { uint w[]; } rec;
void main() {
if (pc.task != 0u) {
rec.w[pc.rec] = min(rec.w[pc.rec], pc.room);
} else {
uint m = min(rec.w[pc.rec + 4u], pc.room);
rec.w[pc.rec + 4u] = m;
rec.w[pc.rec + 9u] = m;
}
}