Files
NX2navi/runtime/vk_mesh_fb.h
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

34 lines
2.5 KiB
C

// The mesh fallback's buffers and its records (vk_mesh_fb.c); the modules are mesh_fb.c's, the draws
// vk_exec_draw.c's ("mesh fallback").
#pragma once
#include "vk.h"
// Creates the buffers and the scan pipeline on first use. 0 when that failed (logged once): the draws are skipped.
int vk_meshfb_init(void);
// The buffer a module's extra storage binding reads or writes (mesh_fb.h MESHFB_CB_*), whole or as much of it as one
// storage binding may span.
VkDescriptorBufferInfo vk_meshfb_buffer(int cb_slot);
uint64_t vk_meshfb_mesh_words(void); // the mesh buffer's size as a binding sees it, in words
// A draw's record, 64 bytes of the record buffer (*rec) at the offset returned: the task dispatch at +0, the mesh
// dispatch at +16, the draw (VkDrawIndirectCommand) at +32. Records the fills and copies that start it, outside a
// pass: the workgroup count from 4 bytes at src_off of src, or `count` when src is VK_NULL_HANDLE. Without a task
// stage that count is the mesh dispatch and the draw's instance count; with one it is the task dispatch, and
// vk_meshfb_scan writes the rest. slot_words: of the draw's mesh program, for the report of a draw the mesh buffer
// was too small for. Returns the number of commands recorded in *cmds.
VkDeviceSize vk_meshfb_record(VkCommandBuffer cb, VkBuffer src, VkDeviceSize src_off, uint32_t count, int has_task,
uint32_t verts, uint32_t slot_words, VkBuffer *rec, int *cmds);
// For a record whose count came from src (a count the GPU wrote): cuts it to what the buffers hold, in the task dispatch
// (task_words, the task stage's payload words) or without a task stage (0) in the mesh dispatch and the instances
// (shaders/meshfb_clamp.comp). Binds its own compute pipeline and set; four commands, between two barriers.
void vk_meshfb_clamp(VkCommandBuffer cb, VkDeviceSize at, uint32_t task_words);
// The pass between the task and the mesh dispatch (shaders/meshfb_scan.comp): binds its own compute pipeline and set.
void vk_meshfb_scan(VkCommandBuffer cb, VkDeviceSize at, uint32_t task_words, uint32_t fan, uint32_t slot_words, uint32_t verts);
// After the record is complete (the copies or the scan, and a barrier): keeps what the draw asked for where the host
// reads it later. One copy command.
void vk_meshfb_note(VkCommandBuffer cb, VkDeviceSize at);
// Draws so far whose programs emitted more than the buffers hold, the records not looked at yet included: call it
// with the device idle (a probe, the shutdown).
uint64_t vk_meshfb_short(void);
void vk_meshfb_shutdown(void); // the device must be idle