### Added
- **A Cache Cap slider on the video settings page**, how much compiled-shader disk this
engine may keep, 128 to 2048 mebibytes in steps of 128. `512 MiB` is the old hardcoded
ceiling and the default. Moving it applies at once, with no pack reload: lowering may drop
unused cached shaders. Written in `vitrail/module-cache-ceiling.txt`.
- **A Shadow Map Scale slider under Video Settings**, on the mod's page beside Max Shadow
Distance. The shadow map is drawn at the chosen fraction of the resolution the pack asked
for, 25 to 100 percent, and the setting outlives whichever pack is chosen. Moving it reloads
the pack, which is what lets the pack be told the smaller number instead of being left to
work against a map it cannot see.
It is a setting of its own rather than something the FSR Render Scale takes along with it,
because of what it does to the picture. The pack works out its shadow blur, its shadow bias
and where it reads the map from the size it was given, so a smaller map is a less defined
shadow, softer where the pack smooths its own and coarser where it does not, and an image
the pack's author never saw. That is a trade worth offering and not worth making on
somebody's behalf, so at 100 percent, which is where it starts, the pack gets exactly the
map it asked for and nothing of the setting runs. The engine says at load when the setting
is in force.
What the render scale reaches and what it leaves alone is now written down, in
`docs/render-scale.md`.
- **A switch that fills the shadow map from a box around you rather than the tight
silhouette.** An empty file `vitrail/box-shadow-cull` in the game folder, or
`-Dvitrail.boxShadowCull=true`. The silhouette stays the default, which is what other loaders
draw. The box was tried as the default, to stop leaf blocks popping at the sun's edge as you
move, and measuring it is why it did not stay: on one wooded scene it drew 875 sections where
the silhouette draws 322, and the frame ran twelve to twenty-eight percent slower depending on
how much stood around. It also stops bounding anything at all once Shadow Distance reaches
your render distance, which is where the slider sits at its maximum.
What the box covers up is a defect of this engine and the switch is not its fix: leaves can go
a frame without their shadow while you walk, if you run a mod that narrows what the game
considers visible. That is being fixed at its cause instead.
- **A switch that hands every sine and cosine a pack writes back to the graphics driver.** An
empty file `vitrail/driver-trig` in the game folder, or `-Dvitrail.driverTrig=true`. They are
normally replaced at load with a helper that keeps its accuracy over a whole world coordinate,
where a driver's own can shed the low bits and show as shimmer. The switch exists so the two
can be compared in one world rather than across two builds, and the log says which of them a
pack load ended up with either way. A pack that defines its own sine keeps it in both states.
### Changed
- **Compute shaders now hit the compiled-module cache on a pack reload.** They used to miss
every time because the disk key hashed the load number the debug name carries. That number
is out of the key. Computes are compiled by this engine, not by the game's shader compiler;
what is kept is the compiled module and its bind table, the same files graphics shaders
already write under `vitrail/modules`. Vulkan pipelines are built each load as before.
- **F3 names the pack the way Iris does.** The profile line is the scanned name or Custom, with
how many options sit outside it, and the shadow line is Sodium's `C: a/b D: d` without this
engine's own cull dialect.
- **The compiling overlay no longer covers F3.** While the debug screen is open, "Compiling
shaders..." rides the Vitrail F3 line instead of the corner. Close F3 and the corner overlay
is as it was.
- **Video-settings labels tell the truth about reload.** Titles are shorter so they fit the
row. Each tooltip says whether the change applies at once, at the next frame, or reloads
the pack.
- **Loading a pack a second time no longer compiles its shaders again.** The compiled module
and the table of what it binds are kept under
`vitrail/modules` in the game folder and read back when the same shader comes round again, so
a warm load does no compiling and no inspecting at all. Editing a shader or moving a pack
setting changes what is asked for, and so does updating the mod, the game or the loader, and
anything that has changed is built from scratch as before. Each release keeps its own folder
and takes the older ones away with it, the whole thing is capped, and the log says how many
shaders came off the disk, how many were built and how much is stored.
**It removes work rather than time.** Measured on one machine: a warm load compiles none of
the two hundred odd shaders a cold one compiles, and the wait before the pack draws is the
same to the second. What a pack load really costs sits somewhere neither this nor the log
line is looking.
- **Loading a pack again no longer rewrites its shaders from scratch.** Turning a pack's GLSL
into the dialect this backend speaks is one of the three things a pack load pays for, and it
is the same answer every time the same pack comes back. What it came to is kept under
`vitrail/translations` in the game folder and read back instead. Editing a shader, moving a
pack setting, changing the shadow map scale, updating the mod or the game, or switching one of
the mod's own measurement switches all change what is asked for, and anything that has changed
is rewritten as before. Each version keeps its own folder and takes the older ones away with
it, the whole thing is capped at a quarter of a gigabyte, and the log says how many programs
came off the disk and how many were rewritten. It removes work rather than time: the wait
before a pack draws is the same, and what changes is that none of it is spent here.
- **A shadow lookup a pack asks the hardware to compare is now compared by the hardware.** A
pack declaring `sampler2DShadow` used to have that comparison rebuilt in shader
arithmetic on every tap, a dozen instructions where a comparison sampler pays one, and a
shadow's blur loop makes many taps per pixel. The comparison now rides the sampler, the pair
Iris binds when a pack asks for its hardware shadow filtering, which every pack that declares
the type does; the picture it computes is the same blend of the same four texels. For a
machine where the sampler road is suspected of a wrong image, a file
`vitrail/soft-shadow-compare` in the game directory, or `-Dvitrail.softShadowCompare=true`,
puts the arithmetic back in one launch, and removing it again takes a pack reload.
- **A patch of this mod that stops fitting the game now refuses to start it, instead of drawing a
wrong picture.** Those patches used to be dropped without a word when a game or Sodium update
moved what they attach to, and what reached the screen was an effect quietly missing or a
surface lit by the wrong program, with nothing in the log pointing at it. The failure now names
itself at launch. The one exception is the line this mod adds to the F3 overlay, which is
allowed to go missing because nothing on screen depends on it.
- **A texture's chain of shrunken copies is rebuilt only when its base has changed.** Packs that
blur or expose through those copies asked for the whole chain to be rebuilt before every pass
that reads one, even when nothing had touched the image in between; two readers in a row now
pay one rebuild instead of two. The copies read are the same ones. Not measured, so this says
work removed and not frames gained.
- **Two pieces of per-frame work on the graphics card are gone, and the picture is the same.**
The far terrain's own depth image is emptied by the pass that draws into it rather than by a
command of its own, which also spares the full stop of the card that such a command carries.
The voxel volumes that follow the camera now copy only the part of themselves that survives
the move, where they used to copy the whole volume. Neither has been measured, so this says
work removed and not frames gained.
- **A handful of values handed to shaders are worked out once a frame instead of once for
every program that asks for them.** Where the sun and the moon are, which way is up, the
End's flash, and the two matrices a pack multiplies its vertices by were all rebuilt from
scratch each time a shader asked, which for a large pack is dozens of times a frame out of
numbers that had not moved in between. They are kept and reused until something they are
built from actually changes. The values handed over are the same ones, to the bit, and this
has not been measured either, so again it is work removed rather than frames gained.
- **The same picture with less repeated work inside the frame.** A pack's geometry program
re-bound every texture it declares for every chunk region, mob piece and particle batch it
drew, where only the two to four that follow the image in hand can change inside one pass;
the rest are now written once, when the pass opens. Beside it: the far terrain's sections are
collected into a list sized from the count Distant Horizons gives rather than grown into one,
and handed on without a copy; a vertex format is searched for this engine's own elements only
until the first one it has not got; and a pass is asked for its name only once everything
cheaper about it has already matched. Whether the frame rate moves is a machine's to measure.
### Fixed
- **AstraLex night skies are round again.** A pack that interpolates a 3x3 matrix between
vertex and fragment, AstraLex's planet among them, was stretched into an oval: this backend
numbers varyings by count, and a matrix occupies several slots. Each matrix is now split into
one vector per column before compile. Complementary never declared one, so it did not show
the oval.
- **Turning Distant Horizons on reloads Complementary and then draws it.** The pack used to
be reread with Distant Horizons present and then refused, because four uniforms stayed
outside a block, so the world dropped to vanilla. The machine symbols are now installed
before the pack is opened, so those uniforms enter the block and the reload draws the
pack. The toggle still reloads; it does not keep the pack on without one.
- **The button that opens a pack's settings is no longer dead until the pack has been loaded
once.** It was live only while a pack was already drawing, so the first pack anybody picks on
a fresh install could not be configured at all: the only way in was to load it at whatever
profile its author shipped, which on a small machine is the one launch that hurts. It is now
live for the pack the list has selected, and pressing it reads that pack, which is parsing and
no work on the graphics card, and puts its settings on screen while the loaded pack goes on
drawing. Setting a heavy pack to its low profile before ever loading it now costs one load
instead of two. A pack that lays no settings out says so instead of opening an empty page.
- **Breaking a block no longer paints flat black cracks over it.** The overlay that spreads as a
block is mined was left to the game, and it multiplies its texture onto what is already drawn;
it was landing on an empty layer instead of on the picture, so every crack came out opaque
black from the first stage rather than darkening the face as it broke. It is drawn through the
pack now, on `gbuffers_damagedblock` and its fallback onto the terrain, which is what a pack
expects to be asked for.
- **A pack written with the old shadow lookups could be translated wrong, without a word.**
Wrapping those lookups shifted the translator's own note of which words are macro names,
which could rename one of them or leave a local variable reading a global value instead.
Nothing in the tested packs reached it.
- **A pack that changes with how humid a biome is no longer sees a desert everywhere.** The
`rainfall` value handed to shaders was always nought, so puddles, wetness and fog that
scale with humidity stayed at their driest in a swamp and a jungle alike.
- **Changing shaderpack without restarting no longer leaves the buffers of the pack before it
in play.** The names a pack gives its `bufferObject` blocks were remembered for the whole
session rather than for the pack that wrote them, so a pack loaded after another could have a
block bound to a buffer the earlier one had declared, at whatever size and contents that one
asked for, or keep a program running against a block nothing binds at all. Complementary
Ultra with world-space reflections on is the pack that declares such a block, and quitting
the game between two packs was the only thing that cleared it.
- **A shadow compute pass that leaves its size to the engine now covers the screen.** A pack
can say how much work such a program does in several ways, and only the one where it
writes the count out itself was read. A program using any other ran as a single small
tile: it filled a few hundred texels, and everything past them kept whatever the frame
before had left, so the effect showed up in one square at the corner and was stale over
the rest of the picture. Every pack tested here writes the count out, so only packs
outside that set could see it. Two smaller things come with it: a pack asking for no work
at all, which is how one of those forms switches a pass off, now dispatches nothing rather
than one tile, and a program whose size cannot be read at all is left out with a line in
the log naming it, rather than guessed at.
- **The log says why a pack is drawing the world with the game's own terrain shader.**
When nothing of the pack reaches the chunk mesh, three quite different things can have
happened: the pack was read and asks for none of the extra vertex data, or its load never
got as far as its chunk programs, or the mesh was built before the pack had been read. All
three used to share one line that named none of them, and the third only showed itself a
world later, as an error about two lists of attributes that said nothing about the order
that made them differ. Each now says which one it was, where it happened.
- **The game no longer crashes when AsyncParticles draws its GPU-accelerated particles under a
shaderpack.** AsyncParticles can move its particles to the GPU and record their draws itself,
into the very pass this mod had opened over the pack's colour targets, with pipelines built
for a single target: the frame died on a colour attachment count mismatch a few seconds into
the world. Those draws now take the pack's own particle programs, rebuilt over
AsyncParticles' vertex layout, which is what Iris draws them with as well.
Optional dependencies
(Sodium) Chloride
Any compatible version
Fabric API
Any compatible version
Developer information
Projects on Modrinth are automatically available through a Maven repository for use with JVM build tools such as Gradle.
maven { name = "Modrinth"; url = "https://api.modrinth.com/maven" }