Skip to content

Add a per-frame triangle budget for new geometry materialization#150

Open
BinqAdams wants to merge 1 commit into
NVIDIAGameWorks:mainfrom
BinqAdams:fix/materialization-budget
Open

Add a per-frame triangle budget for new geometry materialization#150
BinqAdams wants to merge 1 commit into
NVIDIAGameWorks:mainfrom
BinqAdams:fix/materialization-budget

Conversation

@BinqAdams

Copy link
Copy Markdown
Contributor

New geometry materialization (vertex upload, interleave and BLAS build) runs synchronously in the draw submission path. A burst of newly visible meshes, for example when camera rotation brings previously culled objects back into the frustum, therefore lands in a single frame as one monolithic spike. Textures and opacity micromaps already have async streaming and per-frame build budgets respectively; geometry has no equivalent mechanism.

When rtx.materializationBudgetTrianglesPerFrame is greater than zero, new geometry (DrawCallCache misses) is admitted while the frame's running triangle counter is under the budget. The final admission may overshoot by one mesh, so a single mesh larger than the whole budget still loads. Over-budget draws are skipped without creating any state and retried on later frames: original draws through the game's own per-frame resubmission, replacement prims through a new ReplacementInstance::pendingMaterialization pending-work flag that keeps the instance off the preserve path until a pass defers nothing. Deferral trades the spike for one to three frames of pop-in at the frustum edge, where it is effectively invisible.

Default 0 preserves existing behavior exactly.

Testing

Test game: Painkiller Black Edition with a USD mod containing mesh replacements (the case that motivated the change; any content where many replaced or new meshes enter the view at once will do).

  1. Set rtx.materializationBudgetTrianglesPerFrame = 500000 in rtx.conf.
  2. Load a level with many replaced props and rotate the camera in place through a full turn several times, so off-screen objects repeatedly re-enter the frustum.

Before the change: each turn produces frame spikes of roughly 35 ms (measured via Tracy: the dxvk-cs thread stalls in geometry upload and BLAS build for the re-entering meshes, largest single offender 1.68M triangles in the test content).

After the change: the spikes are gone; per-frame new-geometry work is bounded by the budget. Deferred meshes appear within one to three frames. Verified with an instance-lifecycle log that deferred draws are retried and materialize (largest deferral observed resolved in 2 frames), and specifically that replacement prims deferred while their ReplacementInstance is being set up still materialize instead of persisting as holes; level geometry, pickups and effects all present after sustained play, level changes and reloads.

With the option at its default 0, behavior is unchanged.

New geometry materialization (vertex upload, interleave and BLAS
build) runs synchronously in the draw submission path, so a burst of
newly visible meshes, for example after camera rotation brings
previously culled objects back into the frustum, lands in a single
frame as one monolithic spike. Textures and opacity micromaps already
have async streaming and per-frame build budgets respectively;
geometry has no equivalent mechanism.

When rtx.materializationBudgetTrianglesPerFrame is greater than zero,
new geometry (DrawCallCache misses) is admitted while the frame's
running triangle counter is under the budget; the final admission may
overshoot by one mesh so a single mesh larger than the whole budget
still loads. Over-budget draws are skipped without creating any state
and retried on later frames: original draws through the game's own
per-frame resubmission, replacement prims through a new
ReplacementInstance::pendingMaterialization pending-work flag that
keeps the instance off the preserve path until a pass defers nothing.
Deferral trades the spike for one to three frames of pop-in at the
frustum edge.

Default 0 preserves existing behavior exactly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant