Repository navigation
Conversation
On the AGX2 chips a vertex or fragment shader that indexes a large constant array stored the whole array to scratch in every invocation before it read one entry of it. nir_opt_large_constants ran only on the native AGX3 paths and the M5, so on AGX2 the scratch lowering in agx_preprocess_nir() claimed the array, and scratch is private to one invocation. DXVK 3 writes a D3D11 immediate constant buffer as such an array, a Private, NonWritable variable with a constant initializer, and on Honeykrisp does not move it to a buffer itself. Skyrim Special Edition's sun-shadow mask pass has a table of 1005 vec4. Its fragment shader compiled to 5987 instructions with 1054 spills and 16080 bytes of scratch, and its one full-screen draw took 339 ms at 1920x1080, about 165 ns per pixel. The game's world ran at 2.8 fps. Run the existing vertex and fragment branch on every chip. Nothing after it is particular to the native paths: lower_load_constant reads the blob's address from draw.vs_constant_data_addr or draw.fs_constant_data_addr, hk_compile_nir() keeps nir->constant_data with the shader, and hk_flush_shaders() uploads the bound blobs and publishes both addresses, whatever the chip. The same shader becomes 578 instructions with no spills and no scratch, the pass takes 0.49 ms and the game runs at 43 fps. Unchanged: an array the shader writes to is not constant and stays in scratch. A shader with no array above the scratch threshold is left alone, as on the native paths. AGX2 compute keeps its scratch arrays, because only the native dispatch paths publish cs.constant_data_addr. The upload reuse in hk_cmd_upload_constants() stays native-only, so AGX2 uploads a bound blob again at each shader flush. The native AGX3 and M5 conditions are the same as before. Measured on one AGX2 machine with two builds of b7b03c5, with and without this change (debugoptimized, assertions on): - A full-screen 1920x1080 draw whose fragment shader reads one entry of a 1005-entry vec4 table per pixel: 421 ms to 0.31 ms a frame, every pixel as expected in both. The shader goes from 3680 instructions, 1893 spills and 19696 bytes of scratch to 15 instructions. With the table declared as DXVK declares it: 421 ms to 0.44 ms. - 1005 points whose vertex shader reads the table, drawn directly and through a pass-through geometry shader: every point as expected in both, the vertex shader from 3701 instructions to 27. - A fragment shader that writes one entry of the table first: the same shader hash and the same output in both. - Skyrim Special Edition, Proton Experimental (ARM64), DXVK v3.1.1-188, 1920x1080, Ultra preset: 2.8 fps to 43 fps. - The table shaders and the three CI probe shaders compile on the drm-shim profiles g13g, g13x, g14g, g15s, g15c, g15g and g17p. Not measured: Vulkan CTS, any other AGX2 chip on hardware, tessellation, and the native AGX3 and M5 paths on hardware. Closes: omacom#44 Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
[Medium impact] The PR appears safe to merge; no actionable issues were found. SummaryExtends large constant-table lowering to AGX2 vertex and fragment shaders.
Reviews (2) · Last reviewed commit: "hk: read large vertex and fragment const..." · Reviewed by Greptile |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #44.
One commit on
integration/auroraatb7b03c5b3b8a. It runs the existing vertex and fragmentnir_opt_large_constantsbranch on the AGX2 chips too, so a large constant table is read from the shader's constant blob instead of being stored to scratch by every invocation. Skyrim Special Edition through DXVK 3 goes from 2.8 fps to 43 fps.The change
hk_preprocess_nir_internal()inhk_shader.c: the chip condition now guards only the compute arm. The vertex and fragment arm keeps itshk_has_scratch_sized_array()check and its 256-byte threshold, and now applies to every chip.lower_load_constant, the blob thathk_compile_nir()keeps and the upload inhk_flush_shaders()already serve vertex and fragment shaders on every chip; Honeykrisp on AGX2 fills a large constant table in scratch for every pixel: Skyrim SE at 2.8 fps through DXVK 3 #44 has the links.What stays as it was
hk_dispatch_m5_native()andhk_dispatch_g17p_native()publishcs.constant_data_addr, so the pass is not run for it.hk_cmd_upload_constants(), which is still native-only. On AGX2 a bound blob is uploaded again at each shader flush; for the 16 KB table here that is one upload a frame. It is left out to keep this to the gate, and can go in here if wanted.MEASURED
On one AGX2 machine, kernel
linux-aurora 7.2.11.aurora14-1. Two builds:b7b03c5b3b8aas it is, and this head,aecd98f83e8f. Vulkan driver only,debugoptimizedwith assertions, tools stage with LLVM 23, loaded withVK_DRIVER_FILES. Nothing was installed and no boot stack was touched.The standalone reproducer in Honeykrisp on AGX2 fills a large constant table in scratch for every pixel: Skyrim SE at 2.8 fps through DXVK 3 #44, every case
PASSwith no wrong pixel in both builds:What the driver compiled: the fragment shader goes from 3680 instructions, 1893 spills and 19696 bytes of scratch to 15 instructions; the vertex shader from 3701 instructions to 27; the shader that writes to its table keeps the same hash.
Skyrim Special Edition (Proton Experimental ARM64, DXVK
v3.1.1-188-gcf0a0d90f896514, 1920x1080, Ultra preset): 2.8 fps in two runs of the base, 43.4, 42.5 and 42.5 fps in three runs with the change. The shadow mask pass goes from 339 ms to 0.49 ms, its shader from 5987 instructions with 16080 bytes of scratch to 578 with none. These runs used a build of the same tree made before the commit existed.No GPU timeout or fault in the kernel log in any run. The kernel does log an occasional
Job canceled on DRM scheduler teardownwhen one of the reproducer's short cases exits. Over 96 runs per driver it logged 18 such lines with the system package, 15 with the unpatched build and 32 with this head, whose short cases finish sooner; every run passed. It is there without this change, and which job it cancels was not looked into.python3 tools/siliconforest/check.pypasses on this head.The CI probe
.github/mesa-ci/pipeline.cpasses on the drm-shim profilesg13g,g13x,g14g,g15s,g15c,g15gandg17p, with its own three shaders and with the table shaders in place of the interpolation pair. Run without the validation layer, which is not installed here.NOT measured
ci / result: on a first pull request from a fork it waits for a maintainer to start it.🤖 Generated with Claude Code