Skip to content

DXVK-Sarek 1.13.0 "Pacemaker" Released

Latest

Choose a tag to compare

@pythonlover02 pythonlover02 released this 24 Aug 06:49

Unofficial DXVK 1.10.x Build:

This is not an "official" build created by doitsujin/ドイツ人 (Philip Rebohle), the developer of DXVK.
Instead, it is an unofficial continuation of the 1.10.x branch designed to assist users still relying on the 1.10.x releases by backporting per game configurations, fixes and a little more.

Credits:

Full credit goes to doitsujin/ドイツ人 (Philip Rebohle) and everyone that have worked on the dxvk project. You can find the original DXVK repository here: dxvk.

Also, huge thanks to @WinterSnowfall (the d7vk developer), as his work made it possible to bring D3D3, 5, 6 and 7 support to DXVK-Sarek, and he keeps the d7vk side of things up to date release after release.

And a mention to netborg-afps/dxvk-low-latency, which is where the idea for the frame pacing mode in this release comes from. The implementation here is mine and had to be done the Sarek way (more on that below), but the project deserves the credit for the concept and original implementation :).

The "Name":

"Pacemaker", because most of my development time this cycle went into frame pacing, the low latency mode, the frame rate limiter methods and the pacing modes :), even if they are far from being the biggest part of the changelog.

Contributors:

@pythonlover02
@WinterSnowfall
@loathingKernel
@CkNoSFeRaTU

Changelog:

This release is about polish and frame pacing. The two major additions are the frame pacing / low latency mode (together with the new frame rate limiter methods and pacing modes) and the selectable shader compilation method, which finally lets you pick between dyasync, async and none instead of being stuck with whatever the build shipped with. On top of that, d7vk went from v1.9 all the way to v2.1 (including the D3D9 bridge rework), D3D9 got colorkeying support, the memory allocator got a proper per type dynamic chunk sizing rework, the build system was replaced with a Makefile (simply because i prefer it over bash scripts rn), and a truly absurd amount of upstream fixes, validation fixes and backports were integrated across every single module of Sarek. A lot of games that were broken or misbehaving on 1.12.0 should behave much better now. As always, feel free to try your fav games and report anything that doesn't work :).

  • [d3d7] Update D7VK module to v1.9
  • [d3d7] Backport v1.11 code and fix legacy lighting (#44)
  • [d3d7] Backport D7VK v1.12 to Sarek (#52)
  • [d3d7] Backport D7VK v2.0 to Sarek (#58)
  • [d3d7] Backport D7VK v2.1 and the D3D9 bridge rework (#68)
  • [d3d7] Backport fixed function alternate pixel center (#70)
  • [d3d8] Port back latest D3D8 code in DXVK 3.0.1 (#54)
  • [d3d9] Colorkeying support (#71) (thanks @CkNoSFeRaTU)
  • [d3d9] Fix invalid SPIR-V in fixed function colorkey discard
  • [d3d9] Backport FF shader compiler and software cursor fixes (#43)
  • [d3d9, d3d11, dxgi, util] Backport upstream options and behavior
  • [d3d9] Validate box and clear output in Volume::LockBox
  • [d3d9] Pick stencil-aware D24S8 fallback format
  • [d3d9] Parenthesize stencil aspect check in the depth format fallback
  • [d3d9] Lock device in UserDefinedAnnotation::BeginEvent, EndEvent and SetMarker
  • [d3d9] Expose RGBA8 fallback for ARGB back buffer formats
  • [d3d9] Initialize out parameter in GetLastPresentCount stub
  • [d3d9] Zero out the presentation statistics stub output
  • [d3d9] Handle destroyed back buffers in GetBackBuffer
  • [d3d9] Place the front buffer copy at the window position
  • [d3d9] Log GDI DC creation failure in Surface::GetDC
  • [d3d9] Drop implicit flush in UnlockBuffer
  • [d3d9] Skip CS chunk flush if sequence number already reached
  • [d3d9] Don't mark all subresources for readback on mipgen
  • [d3d9] MultiplyTransform is applied immediately, never recorded
  • [d3d9] Dirty alpha test state when rebinding RT0
  • [d3d9] Initialize return pointer before validation in EndStateBlock
  • [d3d9] Use ShouldRecord in BeginStateBlock
  • [d3d9] Do not capture the stream source offset in state blocks
  • [d3d9] Validate pool and usage flags in ValidateBufferProperties
  • [d3d9] Dont request DEVICE_LOCAL for cached dynamic buffers
  • [d3d9] Require both color and depth sample count support for MSAA
  • [d3d9] Reject multisample types the device does not support
  • [d3d9] Validate AdapterFormat and buffer RTypes in CheckDeviceFormat
  • [d3d9] Fix CheckDeviceFormat validation applied to wrong function
  • [d3d9] Drop duplicated argument validation in CheckDeviceFormat
  • [d3d9] Check depth stencil format support in CheckDepthStencilMatch
  • [d3d9] Report the AMD driver dll for unknown vendors
  • [d3d9] Derive the vendor id from the custom vendor id option
  • [d3d9] Reject software device types in GetDeviceCaps
  • [d3d9] Reject device creation for the SW device type
  • [d3d9] Force software vertex processing for REF device types
  • [d3d9] Document the display mode sort order
  • [d3d9] Correct buffer sequence number query documentation
  • [d3d9] Align texture stage count constant
  • [d3d9] Add combined texture count constant
  • [d3d9] Derive the FVF from a vertex element declaration
  • [d3d9] Write single dword vertex elements without a vector cast
  • [d3d9] Validate vertex declaration in indexed user primitive draws
  • [d3d9] Clamp fixed function texcoord count to the vertex decl
  • [d3d9] Leave the locked rect untouched when locking fails
  • [d3d9] Correct the default light direction and diffuse alpha
  • [d3d9] Drop mismatched memory orders on the query reset counter
  • [d3d9] Refresh adapter format tables when entering d3d8 mode
  • [d3d9] Gate W11V11U10 support on the d3d8 compatibility flag
  • [d3d9] Guard display enumeration and dpi awareness behind win32
  • [d3d9] Give dllexport default visibility on non-windows builds
  • [d3d9] Fix sampler count hud item description
  • [d3d9] Reserve part of the reported texture memory
  • [d3d9] Guard against shader constant range overflow
  • [d3d9] Validate depth stencil clear flags
  • [d3d9] Skip clears of empty regions
  • [d3d9] Relax update texture validation for single mip textures
  • [d3d9] Reject invalid stretch rect filters
  • [d3d9] Reject invalid render target and volume texture usages
  • [d3d9] Unbind stale vertex and index buffers when the scene ends
  • [d3d9] Drop redundant shared handle type assignment
  • [d3d11] Validate resource in WriteToSubresource and ReadFromSubresource
  • [d3d11] Skip initialization of tiled buffers
  • [d3d11] Reject tiled 1D textures
  • [d3d11] Return DEVICE_LOCAL only for tiled buffers
  • [d3d11] Dont request DEVICE_LOCAL for cached dynamic resources
  • [d3d11] Reject SO geometry shaders without transform feedback support
  • [d3d11] Null-safe DXGISurface::isSurfaceCompatible
  • [d3d11] Fix DXGI map flag decoding in DXGISurface::Map
  • [d3d11] Null-check out pointer in DXGISurface::GetResource
  • [d3d11] Support null event in Fence::SetEventOnCompletion (later reverted, it caused more trouble than it fixed)
  • [d3d11] Enable meta copy usage for all image view formats
  • [d3d11] Use video processor view dimensions in view switches
  • [d3d11] Return S_FALSE when input layout creation is validation only
  • [d3d11] Exclude min-max filters from depth comparison samplers
  • [d3d11] Drop unused immediate context in GDI readback creation
  • [d3d11] Set ignore graphics barriers from its own option only
  • [d3d11] Clamp buffer slice offsets to the buffer size
  • [dxgi] Forward GetFrameStatistics to the fullscreen swap chain
  • [dxgi] Lock buffer in SetSourceSize
  • [dxvk, d3d9, d3d11] Add frame pacing / low latency mode
  • [dxvk] Add selectable shader compilation method
  • [dxvk] Rework dyasync queue to mutex-based design
  • [dxvk] Yet another small rewrite of dyasync
  • [dxvk] Fix dyasync build on MSVC C++17
  • [dxvk] Track a per-type chunk size and initialize it properly
  • [dxvk] Add minimum and maximum chunk size bounds
  • [dxvk] Declare adjustChunkSize and take a required size in pickChunkSize
  • [dxvk] Grow chunk sizes with demand instead of using a fixed default
  • [dxvk] Try suballocation before creating a dedicated allocation
  • [dxvk] Use a per type dedicated allocation threshold
  • [dxvk] Free empty chunks below the current chunk size
  • [dxvk] Free undersized memory chunks and add DxvkMemoryChunk::size accessor
  • [dxvk] Bump default chunk size to 256 MiB
  • [dxvk] Match upstream behavior, enforce heap budget on discrete GPUs only, not on UMA
  • [dxvk] Skip redundant graphics and compute pipeline binds
  • [dxvk] Batch CS chunk execution and use a separate counter mutex
  • [dxvk] Raise limit on queued command buffers
  • [dxvk] Stop shader reflection at the first function
  • [dxvk] Fix layer offsets when packing multi-layer image data
  • [dxvk] Do not use FB path for depth-stencil copies within an image
  • [dxvk] Fix stencil aspect check when discarding stencil on clear
  • [dxvk] Update render target layouts when changing image layout
  • [dxvk] Fix invalid source stage masks in initImage barriers
  • [dxvk] Use TOP_OF_PIPE instead of 0 for image discard barrier
  • [dxvk] Skip disabled extensions in toNameList
  • [dxvk] Dont query queues for ignored queue families
  • [dxvk] Apply CPU device filter independently of device name filter
  • [dxvk] Ignore CPU device skip when a device name filter is set
  • [dxvk] Default-initialize option struct members, the memory budget option, the tiler mode option and the state cache worker counter
  • [dxvk] Simplify Vulkan struct initialization in meta clear pipelines
  • [dxvk] Move DxvkMemoryAllocator::zeroMappedMemory out of line
  • [dxvk] Drop redundant uuid declaration for MSVC
  • [dxvk] Fix MSVC error
  • [dxvk, util] Backport dxvk.hideIntegratedGraphics
  • [dxvk, util] Backport dxvk.deviceFilter
  • [dxvk, util] Backport dxvk.maxMemoryBudget
  • [dxvk, util] Backport dxvk.tilerMode
  • [dxvk, util] Backport dxvk.zeroMappedMemory
  • [dxvk, util] Backport dxvk.lowerSinCos
  • [dxso] Read usedRTs after finalize to catch SM1 color output
  • [dxbc] Fix dxvk.lowerSinCos crashes
  • [dxbc] Fix invalid compound literal in emitVectorSinCos
  • [dxbc] Use NClamp for output depth clamp
  • [dxbc] Use NClamp for hull shader tess factors
  • [dxbc] Return zero size for out-of-bounds resinfo mip levels
  • [dxbc] Report one LOD for multisampled images in emitQueryTextureLods
  • [dxbc] Emit dot products with a defined operation order
  • [dxbc] Only emit fused mad when instruction is precise
  • [dxbc] Decode the EvalSnapped offset as 4-bit fixed point and as a signed integer
  • [dxbc] Throw on invalid shader stage in emitInit
  • [dxbc] Interleave workgroup memory zero-init across invocations
  • [dxbc] Declare depth image types for one-dimensional textures
  • [dxbc] Use a scalar texel offset for one-dimensional images
  • [dxbc] Bounds check dynamically indexed declared register ranges
  • [spirv] Handle null initializer in newVarInit
  • [spirv] Forward newVar to newVarInit
  • [vulkan] Null out surface handle after destruction
  • [vulkan] Log the selected swap chain color space
  • [util] Guard wine log output behind _WIN32 in emitMsg and getFileName
  • [build] Replace package-release.sh with a Makefile
  • [build] Fix d3d10 and ddraw dependencies (#41)
  • [build] Disable ddraw/d7vk on all architectures that are not x86
  • [meta] Disable ddraw for x86_64 and aarch64 artifacts (#63)
  • [meta] Add artifacts in steamrt (#62) (thanks @loathingKernel)
  • [meta] Use -marm64x to match proton (#67)
  • [meta] Verbose ninja compilation
  • [util] Backport and update several configs from upstream
  • [util] Add frame rate limiter methods and pacing modes
  • [util] Sync dxvk.conf with backported options
  • [util] Match upstream maxFrameRate
  • [util] use tgsm barriers for far cry 5 and new dawn
  • [util] hide gpu vendors instead of spoofing ids in app profiles
  • [util] fix trailing space in the dragon nest option key
  • [util] add splinter cell double agent and astebreed profiles
  • [readme, util] Document frame pacing / low latency mode and remove duplicates
  • [readme, conf] Update to reflect the current changes
  • [readme] Restructure the readme and add a table of contents
  • [readme] Add ARM/Mobile emulation notes and clean up build instructions

Shader Compilation Methods:

Until now you got dyasync and that was it. Starting with this release you can pick the method with dxvk.shaderCompilationMethod in dxvk.conf, or with the DXVK_SHADER_COMPILATION_METHOD environment variable, which takes priority:

  • dyasync (default) the same Dynamic Asynchronous Pipeline Compilation from 1.12.0. The first time a shader is seen it must be compiled synchronously, that is unavoidable and may cause a brief stutter. Every variant after that is deferred: dyasync grabs the closest already compiled pipeline for those same shaders and uses it as a placeholder while the correct variant builds in a background thread, then silently swaps it in once it's ready.
  • async the traditional async behaviour, with some small patches i did to avoid issues. Nothing stands in. Objects whose pipeline is not ready are simply not drawn until compilation finishes, and work is queued to the background threads without any limit.
  • none unpatched 1.10.x behaviour, everything compiles at draw time. Use this as your reference point when something looks like a rendering bug.

dxvk.numShaderCompilerThreads sets how many background threads whichever method is active gets to use, and DXVK_ALL_CORES=1 is still there for CPUs that need every core to get decent throughput.

Why dyasync is the default:

First things first, dyasync is not designed for a Ryzen or for anything remotely modern. It is designed for the CPUs Sarek actually exists to serve: Intel 2nd and 3rd gen i5s and i3s (2500K, 3470, 2120 and friends), Core 2 Duo and Core 2 Quad, old Pentiums and Celerons, AMD Phenom II and the FX series, low power laptop chips of that era, and ARM CPUs running everything through Box64 or FEX. If your CPU has 2 or 4 slow cores and no headroom to spare, that is the machine dyasync was written for.

I know some of you are going to try dyasync on a strong machine, see fps dips, and assume something regressed compared to async. It didn't, so let me explain this properly because it comes up every single time.

Those dips are shader compilation happening at draw time. That is a real cost, and async was not removing it, it was hiding it from you by rendering nothing at all in those moments.

The reason async felt smoother is that fast hardware masks the problem it creates. With plenty of CPU headroom, the unbounded background thread backlog that full async builds up never really starves the game, so it just quietly eats cores and you don't notice. The tradeoff it makes, not rendering objects and effects that aren't compiled yet and piling up a huge thread backlog, doesn't hurt you because your hardware chews through that backlog fast enough that it never becomes an issue.

On weaker CPUs, which is what DXVK-Sarek mainly targets, that exact same backlog can starve the game completely, you end up with nothing on screen and an unplayable mess. dyasync is more conservative by design: it only defers variants, and it always keeps something valid rendering. In exactly those moments it holds higher fps than full async does, and it's safer for multiplayer because nothing ever goes invisible.

The dips settle down a lot once the shader cache is warm. And if you still prefer full async on your machine, that's what the option is there for now, you no longer need a separate build for it.

So the short version: dyasync is slightly worse on powerful PCs, and it avoids the issues async causes on the low end PCs that are mostly what Sarek targets. That is exactly why it is the default.

Warning

Both dyasync and async may produce brief visual inaccuracies, and manipulating shader compilation this way could theoretically be picked up by client-side anticheat. Even if dyasync is the safer of the two, use both in multiplayer games at your own discretion.

Frame Pacing (low latency mode):

This release adds an optional frame pacing mode, controlled with dxvk.framePace in dxvk.conf or the DXVK_FRAME_PACE environment variable.

I want to be clear about where this comes from: the idea is inspired by netborg-afps/dxvk-low-latency, it is not a direct port of it. That project relies on per submission GPU timing and on the asynchronous presenter that upstream DXVK has, and Sarek's Vulkan 1.1/1.2 targeted presenter simply does not have either of those. So I had to do it the Sarek way and adapt the mechanism to what Sarek can actually observe. Credit for the concept goes to them, the implementation and every compromise in it are mine.

  • "max-frame-latency" (default) Sarek's existing, unchanged behaviour. Frame i won't start until frame (i-1)-x has finished, where x is dxgi.maxFrameLatency / d3d9.maxFrameLatency.
  • "low-latency" forces the effective frame latency down to the minimum needed for forward progress, and makes a best effort prediction of when the previous frame will finish (based on a rolling average of recent frame durations) to cut down on unnecessary CPU wake-up jitter. The prediction is never load-bearing for correctness, a wrong guess costs microseconds, not a broken frame.
  • "min-latency" the same minimal frame latency without the predictive sleep. Lowest possible latency, usually at a noticeable fps cost.

dxvk.lowLatencyOffset fine-tunes "low-latency": positive values (in microseconds) delay a frame's predicted start slightly, negative values start it earlier. Clamped to -10000..10000, defaults to 0.

Note

Because Sarek's presenter has no per submission GPU progress telemetry the way upstream DXVK's does, "low-latency" and "min-latency" currently share the same underlying latency reduction mechanism instead of being two fully distinct algorithms. There is also no VRR aware pacing mode and no HUD latency display yet, both of which the upstream project has. I'd like to get there eventually.

Frame Rate Limiter Methods and Pacing Modes:

The frame rate limiter got a proper rework too, adapted from my own AMD Adrenaline / NVIDIA Settings alternative volt. Both are environment only, since the limiter is created before the configuration file is read, and both default to the behaviour DXVK-Sarek has always had. These are separate from dxvk.framePace, which governs CPU frame submission rather than the limiter itself.

DXVK_FRAME_RATE_METHOD selects how each frame's deadline is derived:

  • deviation (default) carries a correction term across frames so sleep inaccuracy averages out over time.
  • timeline holds an absolute cadence, advancing by exactly one interval per frame and resynchronising only after a frame that overran a whole interval.
  • reactive measures each interval from the frame just presented and never tries to catch up.

DXVK_FRAME_RATE_PACING selects how the limiter waits out the remainder of a frame:

  • precise (default) sleeps coarsely, then busy-waits the last stretch. The most accurate, and it keeps a core hot every frame.
  • sliced sleeps in bounded steps and re-measures after each, then busy-waits a short final margin. Nearly as accurate for a fraction of the CPU time.
  • sleep one sleep for the whole remainder. The cheapest, and only as accurate as the platform timer.
  • spin busy-waits throughout.

Note

Under Box64 or FEX, sliced is usually the better choice. The busy-wait in precise competes with the game for a core it needs, which matters a lot more on emulated ARM CPUs than the small accuracy gain does.

Memory Allocator Rework:

The old allocator in 1.10.x used a fixed chunk size of 128 MiB for every resource type. On integrated GPUs (iGPUs) that share system memory or have only a small VRAM budget, that easily wasted memory and could push games into out-of-memory (OOM) crashes. The new dynamic allocator removes that fixed size. It tracks a per-type chunk size, starts as small as possible, and grows in steps as demand actually requires, up to a 256 MiB maximum. It also frees empty and undersized chunks, and tries sub-allocation before falling back to dedicated allocations.

This behaves somewhat like the chunk sizing in upstream DXVK 2.4, as these changes were adapted from there. It is not a perfect solution, but it is a clear improvement over the old 1.10.x behaviour.

That change significantly reduces the memory footprint and gets many previously OOM-prone games running on iGPUs that 1.10.x could not handle. It is not a complete fix though. On iGPUs with extremely tight memory limits, such as old Intel HD Graphics or very low-end AMD APUs, OOM can still happen under heavy load. Fully fixing those cases would require backporting upstream memory defragmentation. On Sarek target hardware, that may not work at all, or it may come with a noticeable performance hit. If it does land, it will most likely need to be opt in behind a config or environment variable. That is something for the next release. For now, the current allocator is good enough for most cases.

D3D3, 5, 6 and 7 (D7VK v2.1):

The d7vk module went from v1.9 all the way to v2.1 during this cycle, including the D3D9 bridge rework, the legacy lighting fix, the fixed function alternate pixel center backport and everything in between. Massive thanks to @WinterSnowfall for keeping this in sync, all of that work is his.

Do note that ddraw/d7vk is now built for x86 only. It was never in a usable state on x86_64 or aarch64 and shipping it there only caused confusion, so the artifacts no longer include it on those architectures.

New Build System:

package-release.sh is gone, replaced by a Makefile. Every build target is a file now, so make only rebuilds what actually changed, everything lands under build/, and make clean is a single rm -rf. This was done simply because i started to like makefiles :).

Command What it builds
make build/x64 and build/x32
make x64 64-bit DLLs only
make x32 32-bit DLLs only
make dist the sources with build/ populated, in build/dist/
make release tarball in releases/, host toolchain
make release-container the same, built inside the SteamRT sniper SDK
make clean rm -rf build releases

The meson build directories stay in build/build.32 and build/build.64, so ninja install inside those still works exactly as before. The artifacts on the Actions tab are make dist trees now.

Using DXVK-Sarek with Proton-CachyOS:

Nothing changed here since 1.12.0, Proton-Sarek is still discontinued and Proton-CachyOS is still the only officially supported way to use DXVK-Sarek with Proton.

To use DXVK-Sarek with Proton-CachyOS you have to add PROTON_DXVK_SAREK=1 and to also use the added D3D3, 5, 6 and 7 support PROTON_DXVK_SAREK=1 PROTON_D7VK_DDRAW=1.

Hope this clarifies things :)

Extras:

If you'd like to support my work in the FOSS community, you can do so by contributing to any of my projects or by donating.
Every contribution no matter the amount is greatly appreciated and helps keep these tools alive, maintained, and evolving.

ko-fi

That's all for now, thank you for using my projects! If you can, please consider donating, and as always, GLHF!

Release: