Skip to content

panDXVK v01

Latest

Choose a tag to compare

@isygold isygold released this 15 Oct 10:05
· 3 commits to main since this release

panDXVK v01

Summary

What this release targets. v01 is a compatibility build first, with the stability
fixes alongside it. The Sarek v1.14.1 sync carries the compatibility gain — three and a half
years of upstream renderer and state-handling fixes — and the BC→ASTC transcode exists so
textures display at all on Mali. Stability comes from the teardown and device-detachment
fixes and from the GPL library path disabling itself rather than crashing after repeated
link failures. The asynchronous pipeline compiler and the parallel transcode are where the
performance lives, and both are off by default: with no setting, the first draw that
needs a pipeline builds it inline. Read v01 as a correctness build that you can make faster,
not a fast one.

The first official release of panDXVK, and the first build not based on DXVK 1.10.3. The
code base is now synchronised with Sarek v1.14.1, which brings in roughly three and a half
years of upstream work alongside our panVK-specific pipeline compiler and parallel
BC→ASTC texture transcode. This build runs correctly on some panVK versions and not on
others — the difference is a driver capability, not a packaging fault. Read Notes before
installing, and check that your panVK build is one of the working ones.

Key Features

  • Sarek v1.14.1 base — the translation layer now tracks Sarek rather than DXVK 1.10.3, gaining lock-free pipeline instance lookup, improved state handling and the upstream renderer fixes accumulated since 2022
  • gplasync pipeline compiler — asynchronous pipeline compilation built on VK_EXT_graphics_pipeline_library, so a pipeline is built as libraries and linked instead of as one monolithic object; validated in back-to-back comparison against both upstream and Sarek's dyasync, and chosen for this release. Opt-in via dxvk.gplAsyncMode / PANDXVK_GPLASYNC — synchronous by default (see Configuration)
  • Parallel BC→ASTC transcode — block-compressed textures are transcoded to ASTC across all cores at upload time; bit-exact against the reference decoder on all 13 format cases, and measured at 3.11–3.63× the throughput of the single-threaded path
  • panVK-only targeting — Adreno devices are filtered out at instance creation, and the feature gate keys on Mali vendor ID 0x13b5, so desktop GPU assumptions never enter the path
  • On-device telemetry — optional CSV timeline and report files for diagnosing stalls, off by default

Installation

  1. Download merged.zip (manual DLL install) or pandxvk-v01.wcp (launcher install)
  2. Replace the existing panDXVK DLLs with the ones from the archive
  3. Set the environment variables described in Configuration if your panVK build reports BC support
  4. Launch a game as usual

Configuration

Transcode

The transcode path is gated on a runtime capability check, so on some panVK builds the
environment variables below are not optional — without them the game will attempt to upload
raw BC textures the driver cannot sample, which is the usual cause of black or garbled
textures on those builds.

Variable Values Effect
PANDXVK_FORCE_TRANSCODE 1, or any value other than unset/empty/0 Forces BC→ASTC transcode even when the driver claims BC support. Required on builds where a BC wrapper layer fakes the feature. Adds CPU cost and ASTC loss — do not set it on builds that already transcode automatically.
PANDXVK_TELEMETRY 1 Enables the CSV timeline and report writer
PANDXVK_REPORT_DIR path Directory for telemetry output

⚠️ Do not pair the transcode with an updated wrapper BCN layer.

Charan's build (GunaCharanTeja/WinlatorMali, branch bionic-mali-1.0) carries an
updated wrapper BCN layer that is already verified working as intended — it performs the
same BC→usable-texture conversion in effect that panDXVK's transcode performs. Setting
PANDXVK_FORCE_TRANSCODE=1 alongside it puts both mechanisms on the same textures, and
they conflict.

Use one or the other, never both. If your setup's wrapper BCN layer is already
delivering correct textures, leave PANDXVK_FORCE_TRANSCODE unset. Set it only where a
wrapper advertises textureCompressionBC but its layer does not produce working
textures — in that case the flag is what activates BC→ASTC.

Pipeline compilation

Compilation is synchronous by default — the draw that needs a pipeline builds it inline
and pays the cost on that frame. Every option below is opt-in, and none of them is required
for a normal setup. Each can be given as a dxvk.conf key or as the environment variable
listed beside it.

dxvk.conf key Environment variable Default Effect
dxvk.enableAsync PANDXVK_ASYNC False Compiles pipelines on worker threads instead of stalling the draw
dxvk.enableGplAsync PANDXVK_GPLASYNC False The same, using graphics pipeline libraries. Consulted only when gplAsyncMode is 0, in which case it is treated as mode 1
dxvk.gplAsyncMode PANDXVK_GPLASYNC 0 0 off · 1 async · 2 async with graphics pipeline libraries. Any value ≥ 1 turns enableGplAsync on. The two live modes are described below the table.
dxvk.enableDyAsync PANDXVK_DYASYNC False Dyasync: draws a fallback pipeline for the render pass while the real one compiles, instead of dropping the draw. The first draw of a pass still compiles inline, because no fallback exists yet. When set it takes the branch over PANDXVK_ASYNC
dxvk.numAsyncThreads — 0 Worker threads. 0 picks half the CPU cores, clamped to 1–8
dxvk.asyncLog PANDXVK_ASYNC_LOG False Logs compilation to the DXVK log, and warns on the first ten draws dropped for invalid pipeline state
— PANDXVK_GPL_FASTLINK unset Experiments with the faster GPL link path

The two live modes. 0 does nothing. The values that actually change behaviour differ in
how a missing pipeline gets built:

  • 1 — async, full compile. A draw that needs a pipeline state not seen before is queued
    to worker threads and compiled as one monolithic pipeline; the draw is skipped until it
    lands. Every pipeline compiled in the background is also written to the DXVK state cache, so
    the next launch precompiles them at startup and skips far fewer draws. dxvk.enableAsync on
    its own now writes that cache the same way, so its skipped draws no longer recur on every
    launch. With mode 2 off, mode 1 and dxvk.enableAsync therefore take the same path, and
    mode 1 is kept so existing configurations and the
    panDXVK: async=… gplasync=… startup line keep describing themselves as they did.
  • 2 — async, build libraries and link. The same worker threads, and the same state-cache
    write, but instead of one monolithic pipeline the four stages are built separately and then
    linked: vertex input, pre-raster, fragment shader, fragment output. At startup it probes the
    driver for VK_EXT_graphics_pipeline_library, fast linking and independent interpolation
    decoration, and logs which of the three it found; if any is missing it quietly runs mode 1
    instead. If linking proves unreliable in practice it falls back to a full compile per
    pipeline and turns the library path off by itself after 8 such failures, saying so in
    the log — asynchronous compilation stays on, only the library path stops.

Only mode 2 can report library statistics, and it does so at shutdown: libraries created
and reused per stage, pipelines linked, fallbacks to full compile, library time, link time,
and whether the library path was still on when the device went away.

The startup line panDXVK: async=<0|1> gplasync=<0|1|2> reports what was actually picked
up, so the effective setting can be read from the log instead of assumed. Where mode 2
is requested the following line reports whether the driver offered the library feature,
fast linking and independent interpolation decoration, and which of the three it fell back
to.

Set everything the same way as any other DXVK variable — either in dxvk.conf, or as an
environment variable such as PANDXVK_FORCE_TRANSCODE=1 in the container's environment
before launch. Everything else is unchanged — normal setups work as they always have.

Changelog

  • Added: Sarek v1.14.1 base — lock-free graphics pipeline instance lookup with instance, overflow and fallback maps, VK_EXT_graphics_pipeline_library plumbing, the DXVK_SAREK_STRICT diagnostic mode, and the upstream fixes and state handling landed since DXVK 1.10.3
  • Added: parallel BC→ASTC transcode, bit-exact against the reference decoder on all 13 format cases and 3.11–3.63× faster than the single-threaded encoder
  • Added: PANDXVK_FORCE_TRANSCODE, PANDXVK_TELEMETRY, PANDXVK_REPORT_DIR and PANDXVK_GPL_FASTLINK
  • Changed: the pipeline compiler is panDXVK's gplasync implementation, kept ahead of Sarek's dyasync after back-to-back comparison
  • Changed: the graphics pipeline keeps our GPL library keying and library cache alongside Sarek's lock-free instance maps, rather than either side alone
  • Changed: D3D11 deferred and immediate contexts now report a full D3D11_MAPPED_SUBRESOURCE zero and reset the pending image slice when a map fails, instead of clearing only pData
  • Changed: device filtering takes the 1.14 two-argument constructor, and the immediate and deferred contexts use the 1.14 Flush(contextId, flags) signature
  • Added: PANDXVK_DYASYNC / dxvk.enableDyAsync, which draws a fallback pipeline for the render pass while the real one compiles instead of dropping the draw; off unless set, and it takes the branch over PANDXVK_ASYNC
  • Changed: dxvk.enableAsync now writes the state cache after a successful compile, as the gplAsync modes and the synchronous path already did, so its skipped draws are precompiled next launch instead of recurring
  • Removed: dxvk.shaderCompilationMethod, whose "dyasync" default could only have switched dyasync on for everyone who never asked for it, and Sarek's DxvkAsyncCompiler, which was never constructed and existed only to read dxvk.numShaderCompilerThreads
  • Fixed: teardown now closes the telemetry session before waitForIdle() records the teardown-time GPU counters, so they are no longer attributed to the preceding session
  • Fixed: device destruction during DLL process detachment returns before waiting on command-stream threads that no longer exist

Notes

This release does not work on every panVK build, and the difference is a driver capability
rather than an installation problem.
Transcode is enabled only when three conditions hold
at once:

  1. the adapter is Mali (vendor ID 0x13b5)
  2. the driver reports textureCompressionASTC_LDR
  3. either the driver does not report textureCompressionBC, or PANDXVK_FORCE_TRANSCODE is set

The three failure modes are distinct, and the environment variable matters for exactly one
of them:

  • Driver reports no BC and has ASTC — transcode enables by itself. Nothing to set.
  • Driver reports BC because a wrapper layer fakes the feature — the gate sees BC, leaves
    transcode off, and the game uploads BC textures the wrapper then has to cope with. This is
    the black or garbled texture case. Set PANDXVK_FORCE_TRANSCODE=1. This is the
    situation where the environment variable is essential rather than a tuning knob.
  • Driver reports no ASTC — transcode is impossible and no environment variable changes
    that. Do not expect this build to run correctly.

One wrapper-side setting is worth checking before you start, and it is easy to confuse with
the BC wrapper discussed above: WRAPPER_NO_PATCH_OPCONSTCOMP. It is a wrapper setting,
not a panDXVK one — panDXVK contains zero references to it, can neither see nor set it, and
cannot compensate for it from a log afterwards. Winlator Mali ships it defaulted to 1, and
Bannerlator exposes the same toggle as "Don't patch OpConstantComposite". The value
published for panDXVK is WRAPPER_NO_PATCH_OPCONSTCOMP = 0, so check it before the
session
, not after it.

Two cautions. The short spellings WRAPPER_NO_PATCH and wrapper_no_patch are read by
nothing — only the full name reaches the wrapper — so a setting written under either short
form does nothing at all. And its effect is recorded here only as part of a stack that
worked in the field (this variable + panVK + panDXVK together, reported by Lloyd), not
as a cause for any one run's behaviour: an earlier thread blamed it for a black screen and
that attribution was later discarded, because the value was held constant while only the
driver changed and the symptom flipped.

To see which case you are in, enable debug logging and read the
panDXVK: BC→ASTC gate: BC=<0|1> ASTC_LDR=<0|1> force=<0|1> -> transcode <ENABLED|disabled>
line. It states the verdict directly.

Forcing transcode where the wrapper path already works costs CPU time and a small amount of
texture quality, so leave it unset unless you are seeing the symptom.

Pipeline compilation is synchronous unless you opt in, which is the opposite of what the
feature list above might suggest. With no setting, the first draw that needs a given
pipeline state builds it inline and pays the cost on that frame. Setting
dxvk.enableAsync, dxvk.enableGplAsync or dxvk.gplAsyncMode hands that work to worker
threads instead. The trade is that the draw is skipped or rendered with a substitute until
the real pipeline is ready — the multi-second hitch on first use of a material becomes a
brief lower-detail frame, and titles sensitive to a skipped first draw may show a
one-frame artefact on scene load. dxvk.gplAsyncMode = 2 is the safe thing to try first: it
probes the driver for graphics pipeline libraries, says in the log which of them it found,
does not require them, and switches the library path off by itself if linking keeps failing —
so it degrades rather than breaking. Use dxvk.enableAsync instead if you want worker
threads without graphics pipeline libraries at all. Confirm what the game actually took from
the panDXVK: async=<0|1> gplasync=<0|1|2> startup line rather than from your config.

PANDXVK_DYASYNC=1 or dxvk.enableDyAsync = true selects dyasync: rather than dropping a
draw whose pipeline is not ready, it hands back a pipeline already compiled for the same
render pass and queues the real one, sharing PANDXVK_ASYNC's worker threads and creating no
pool of its own. The fallback map fills as the frame proceeds, so the first draw of each pass
still compiles inline — that is what seeds it, and every state vector after it draws. It is
off unless you ask for it, and where it and PANDXVK_ASYNC are both set it takes the branch.

dxvk.shaderCompilationMethod no longer exists. Its three values could not express gplasync
mode 1 against mode 2, and its "dyasync" default would have selected dyasync for anyone
who had never set anything.

Direct3D 9 block-compressed textures are not transcoded in this release. DX9 titles that
upload BC textures on a panVK build without BC support will not display them correctly. This
is a known gap rather than a design decision — the DX9 texture, initializer and view paths
carry no remap — and it is deferred: it is expected to be open to work in a later update.
DX9 BC titles should be treated as unsupported for now, not as permanently broken.

This release is built from a large cross-project merge that has passed structural
verification — no unresolved conflicts, balanced sources, and no references to removed
symbols — and the CI build is the gate that confirms it compiles. If the build for this tag
is not green, treat the release as unreleased and wait for the fix.

Credits

Testers

None of the findings recorded in this release were measured by us. They were produced by testers running these builds on Mali hardware we cannot test on ourselves, and every diagnosis in the early releases traces back to their files. Where something is described as reported rather than independently verified, that is deliberate — it is their observation, recorded as they gave it.

  • Gustave (Mali-G52) — the most consistent logger of the project. Nine Sols, Silksong and Sugary Spire logs, plus the wine logs that named the early crash. Delivered the 9-zip A/B matrix (3 games × {no force, force wrapper 0, force wrapper 1}); first reported the in-game texture-corruption pattern and the "hazy fog" artifact that subsequently drove a dedicated ground-truth investigation; measured the RAM drop twice, both runs landing in the 5–8% band.
  • Us5rman (Mali-G615) — AIO/FPS baselines and the FF7, MOTORSLICE and NFS reports that mapped the early territory. Author of PR #1, and the one behind the asynchronous pipeline idea — see the contributor credit above.
  • @UriYuanKerr69 (Mali-G52) — Cult of PiN on the v2 and v3 builds with screenshots, Dead Cells, Streets of Rogue and Loopler reports.
  • LORD (Mali-G720) — Silksong and long-session NFS13 logs on new silicon.
  • Lloyd (Mali-G615) — DMC5 and GTA V runs, crash forensics and shader dumps. Ran the stock DXVK 1.10.3 control on the same driver and same game, which isolated panDXVK itself as the variable rather than panVK or the blob driver. Established that the real variable name is WRAPPER_NO_PATCH_OPCONSTCOMP and not the shorter spellings, and found the WRAPPER_NO_PATCH_OPCONSTCOMP + PanVK + panDXVK stack that fixed the misrendering titles. Maintains the GTA V personal build, panDXVK-lloyd262.
  • DUCKTEN (Mali-G615) — NFS and AC3SP sessions.
  • Charan — GunaCharanTeja/WinlatorMali, branch bionic-mali-1.0. His wrapper BCN layer is the reported working exception to the otherwise unimproved BCN software layer, and the direct basis for the transcode/wrapper conflict warning in the Configuration section above.

Upstream DXVK Reference