Skip to content

Instantly share code, notes, and snippets.

@manciuszz
Last active July 1, 2023 01:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save manciuszz/eec70cc83db7b557c49cc994b37d20a8 to your computer and use it in GitHub Desktop.
Save manciuszz/eec70cc83db7b557c49cc994b37d20a8 to your computer and use it in GitHub Desktop.
'Vampire: The Masquerade - Bloodhunt' performance tweaking

Performance Tweaking

Vampire: The Masquerade - Bloodhunt

Before we get into the configuration details...

Quick warning about compiling shaders

The compiling of shaders is supposed to be a one-time process, so when you see the following icon in-game:
Optimizing Shader Cache
Expect some freezing for brief moments. This is normal behavior.

Your goal is to achieve stable frame rates in all situations!

image

Improving performance and reducing strain on the CPU

To improve performance, reduce the strain on the CPU, and reduce the impact of shader compilation on gameplay, try the following:

Location: %LocalAppdata%\Tiger\Saved\Config\WindowsNoEditor

  1. Use the DeviceProfiles.ini file to:

    • Enable more Unreal Engine PSO cache;
    • Tweak the speed at which stuff is cached, so that when you do compile shaders in-game they wouldn't freeze your game for seconds;
    • Reduce the texture LOD (Level-Of-Detail):
      • This is because CPU has to manage and sort through a large amount of data related to textures, such as texture coordinates, lighting information, and other properties. Reducing the texture LODs will result in less data for the CPU to manage, and therefore reduce its strain. This can also free up more CPU resources for other tasks, such as managing game logic, AI, animations, and other systems that are heavily dependent on the CPU.
  2. Use the Engine.ini file to:

    • May or may not increase input lag due to r.OneFrameThreadLag=1 (That's the game default).
      • Remove or set to '0' this CVAR if input lag is unbearable.
    • Optimize shader compilation;
    • Force disable debug logs to reduce Disk I/O;
    • Force disable mouse acceleration;
    • Disable shadows;
    • Reduce the resolution image by 10% without introducing blur;
    • Reduce object view distance by 20% without introducing object pop-in.
    • Reduce the number of particles emitted in action scenes;
    • Reduce the cost of rendering decals in the scene;
    • Perform fewer calculations to render refraction effects without making the saboteur's completely invisible;
    • Use less complex skeletal meshes;
    • Reduce the overall performance cost of tessellated meshes;
    • [/Script/Engine.StreamingSettings] - Adjust the loading and unloading of levels and their components during runtime;
      • These settings should be heavily based on hardware. Each system will probably produce vastly different results.
      • However, the general effect should be that you can trade higher load times for less stutters during gameplay.
    • Plus some other experimental tweaks that might get removed in the future.
  3. Use the GameUserSettings.ini file to:

    • Set sg.ShadingQuality=0 to control the shading quality of the scenes. We want to use the least processing power possible for shaders;
      • Make sure to delete or rename %LocalAppdata%\Tiger\Saved\*.ushaderprecache files if you mess with this. The game will recompile them using the new setting.
    • Note: sg.ShadingQuality is set to a value of 3 by default. You can't adjust it using in-game UI.

CVARs that break the game

s.LevelStreamingActorsUpdateTimeLimit - if set to a very close value to 0, makes you fall below the map;
r.CascadeParticleDetailMode=0 - removes all particles from the game and might result in crashes during some situations;
r.DetailMode=0 - removes some objects from the map, making them see through;
r.TranslucencyVolumeBlur=0 - makes saboteurs stop rendering altogether when they go invisible;
r.ViewDistanceScale - value close to 0 makes you stop rendering NPCs.
r.EarlyZPass=0 - screws with object occlusion, makes game completely disorienting and unplayable
r.CustomDepth=0 - disables the weapon aura colors
a.Budget.Enabled=0 - disables the animation budget, meaning after the budget is spent, you won't be able to execute animations, making the game unplayable.
fx.MaxCPUParticlesPerEmitter=0 - disables all CPU rendered effects, creating desyncs and game breaking bugs > fx.MaxNiagaraCPUParticlesPerEmitter=0 - disables all Niagara CPU rendered effects, same reason as with the CPU counter part, just felt less buggy?
r.SelectiveBasePassOutputs=1 - stops rendering objects
r.ForwardShading=1 - stops rendering objects
r.SeparateTranslucency=1 - this cvar when misconfigured can disable weapon outlines

Outside the game possible tweaks:

  1. Cap your framerate.
    • I recommend using RivaTuner Statistics Server.
    • The in-game frame limiter isn't really stable in terms of holding good frame times.
    • For example: I've got a 300Hz refresh rate laptop display. However, I cap 'bloodhunt' FPS using RTSS to 100.
  2. Enable NVIDIA Shader Cache using NVIDIA Profile Inspector or NVIDIA Control Panel;
    • Should be already enabled for most games by default.
  3. Disable DirectX 12 Shader Cache compilation by deleting or replacing D3DSCache.dll component;
    • This would result in DirectX 12 games not being able to compile DX12 shader cache, because the API to do that would not be available.
    • There are multiple ways to go around this:
      • Add an empty D3DSCache.dll file near the games executable and hope the game tries using it first;
      • If that doesn't work, you'd have to use a system-wide solution, which involves messing with /Windows/System32 folder and TrustedInstallers.
    • Modify D3DSCache.dll with a hex editor to increase the inherent shader cache file size limits;
      • Unfortunately, most ANTI-CHEAT software (like EAC) will flag the component as 'untrusted system file' and don't inject it for safety reasons. However, you will still be able to play without any issues, so that is also another way on how to disable shader cache.
  4. Downgrade STEAM Client to a version that still supports the '-no-browser' flag: https://gist.github.com/manciuszz/4e345e89facbf11c75eb3f09fa0b1952
    • ... or you can suspend steamwebhelper.exe processes using System Informer or other tool;
    • This will reduce the amount of CPU cycles STEAM client will consume at all times.
    • It doesn't affect the launch of games.
  5. Remove access from %LocalAppdata%\Tiger\Saved\Logs folder, so the game can't write to it.
    • This will lead to less Disk I/O, which could potentially reduce some I/O related stutters.
    • This wouldn't be necessary, if we could totally disable game logs using Engine.ini cvars.
      • You can create these batch scripts in %LocalAppdata%\Tiger\Saved\Logs folder to make it easier:
        •  ::Disable Write-Access.bat
           @echo off
           icacls . /T /deny %username%:(WD,AD,WA,WEA)
        •  ::Enable Write-Access.bat
           @echo off
           cacls . /e /c /g %username%:f
  6. A system with atleast 32GB of physical RAM can play this game directly from a RAM using a RAM drive. This would result in improved load times, faster asset streaming and lower CPU usage due to faster Disk I/O.

HitCount

[WindowsNoEditor DeviceProfile]
CVars=D3D12.PSO.DiskCache=1
CVars=D3D12.PSO.DriverOptimizedDiskCache=1
CVars=r.ShaderPipelineCache.Enabled=1
CVars=r.ShaderPipelineCache.StartupMode=1
CVars=r.ShaderPipelineCache.PreOptimizeEnabled=1
CVars=r.ShaderPipelineCache.GameFileMaskEnabled=0
CVars=r.ShaderPipelineCache.BatchSize=50
CVars=r.ShaderPipelineCache.BackgroundBatchSize=1
CVars=r.ShaderPipelineCache.PrecompileBatchSize=50
CVars=r.ShaderPipelineCache.BatchTime=1
CVars=r.ShaderPipelineCache.BackgroundBatchTime=1
CVars=r.ShaderPipelineCache.PrecompileBatchTime=0.5
CVars=r.ShaderPipelineCache.AlwaysGenerateOSCache=0
[/Script/Engine.TextureLODSettings]
TextureLODGroups=(Group=TEXTUREGROUP_World,MinLODSize=128,MaxLODSize=128,MinMagFilter=point,MipFilter=point,HighPriorityLoad=0,MipGenSettings=TMGS_NoMipmaps,NumStreamedMips=0)
TextureLODGroups=(Group=TEXTUREGROUP_WorldNormalMap,MinLODSize=1,MaxLODSize=1,MinMagFilter=point,MipFilter=point,HighPriorityLoad=0,MipGenSettings=TMGS_NoMipmaps,NumStreamedMips=0)
TextureLODGroups=(Group=TEXTUREGROUP_WorldSpecular,MinLODSize=1,MaxLODSize=1,MinMagFilter=point,MipFilter=point,HighPriorityLoad=0,MipGenSettings=TMGS_NoMipmaps,NumStreamedMips=0)
TextureLODGroups=(Group=TEXTUREGROUP_Character,MinLODSize=128,MaxLODSize=128,MinMagFilter=point,MipFilter=point,HighPriorityLoad=0,MipGenSettings=TMGS_NoMipmaps,NumStreamedMips=0)
TextureLODGroups=(Group=TEXTUREGROUP_CharacterNormalMap,MinLODSize=1,MaxLODSize=1,MinMagFilter=point,MipFilter=point,HighPriorityLoad=0,MipGenSettings=TMGS_NoMipmaps,NumStreamedMips=0)
TextureLODGroups=(Group=TEXTUREGROUP_CharacterSpecular,MinLODSize=1,MaxLODSize=1,MinMagFilter=point,MipFilter=point,HighPriorityLoad=0,MipGenSettings=TMGS_NoMipmaps,NumStreamedMips=0)
TextureLODGroups=(Group=TEXTUREGROUP_Weapon,MinLODSize=128,MaxLODSize=128,MinMagFilter=point,MipFilter=point,HighPriorityLoad=0,MipGenSettings=TMGS_NoMipmaps,NumStreamedMips=0)
TextureLODGroups=(Group=TEXTUREGROUP_WeaponNormalMap,MinLODSize=1,MaxLODSize=1,MinMagFilter=point,MipFilter=point,HighPriorityLoad=0,MipGenSettings=TMGS_NoMipmaps,NumStreamedMips=0)
TextureLODGroups=(Group=TEXTUREGROUP_WeaponSpecular,MinLODSize=1,MaxLODSize=1,MinMagFilter=point,MipFilter=point,HighPriorityLoad=0,MipGenSettings=TMGS_NoMipmaps,NumStreamedMips=0)
TextureLODGroups=(Group=TEXTUREGROUP_Vehicle,MinLODSize=128,MaxLODSize=128,MinMagFilter=point,MipFilter=point,HighPriorityLoad=0,MipGenSettings=TMGS_NoMipmaps,NumStreamedMips=0)
TextureLODGroups=(Group=TEXTUREGROUP_VehicleNormalMap,MinLODSize=1,MaxLODSize=1,MinMagFilter=point,MipFilter=point,HighPriorityLoad=0,MipGenSettings=TMGS_NoMipmaps,NumStreamedMips=0)
TextureLODGroups=(Group=TEXTUREGROUP_VehicleSpecular,MinLODSize=1,MaxLODSize=1,MinMagFilter=point,MipFilter=point,HighPriorityLoad=0,MipGenSettings=TMGS_NoMipmaps,NumStreamedMips=0)
TextureLODGroups=(Group=TEXTUREGROUP_Cinematic,MinLODSize=128,MaxLODSize=128,MinMagFilter=point,MipFilter=point,HighPriorityLoad=0,MipGenSettings=TMGS_NoMipmaps,NumStreamedMips=0)
TextureLODGroups=(Group=TEXTUREGROUP_Effects,MinLODSize=1,MaxLODSize=1,MinMagFilter=point,MipFilter=point,HighPriorityLoad=0,MipGenSettings=TMGS_NoMipmaps,NumStreamedMips=0)
TextureLODGroups=(Group=TEXTUREGROUP_EffectsNotFiltered,MinLODSize=1,MaxLODSize=1,MinMagFilter=point,MipFilter=point,HighPriorityLoad=0,MipGenSettings=TMGS_NoMipmaps,NumStreamedMips=0)
TextureLODGroups=(Group=TEXTUREGROUP_Skybox,MinLODSize=128,MaxLODSize=128,MinMagFilter=point,MipFilter=point,HighPriorityLoad=0,MipGenSettings=TMGS_NoMipmaps,NumStreamedMips=0)
TextureLODGroups=(Group=TEXTUREGROUP_UI,MinLODSize=128,MaxLODSize=128,MinMagFilter=point,MipFilter=point,HighPriorityLoad=0,MipGenSettings=TMGS_NoMipmaps,NumStreamedMips=0)
TextureLODGroups=(Group=TEXTUREGROUP_Lightmap,MinLODSize=128,MaxLODSize=128,MinMagFilter=point,MipFilter=point,HighPriorityLoad=0,MipGenSettings=TMGS_NoMipmaps,NumStreamedMips=0)
TextureLODGroups=(Group=TEXTUREGROUP_Shadowmap,MinLODSize=1,MaxLODSize=1,MinMagFilter=point,MipFilter=point,HighPriorityLoad=0,MipGenSettings=TMGS_NoMipmaps,NumStreamedMips=0)
TextureLODGroups=(Group=TEXTUREGROUP_RenderTarget,MinLODSize=1,MaxLODSize=1,MinMagFilter=point,MipFilter=point,HighPriorityLoad=0,MipGenSettings=TMGS_NoMipmaps,NumStreamedMips=0)
TextureLODGroups=(Group=TEXTUREGROUP_MobileFlattened,MinLODSize=1,MaxLODSize=1,MinMagFilter=point,MipFilter=point,HighPriorityLoad=0,MipGenSettings=TMGS_NoMipmaps,NumStreamedMips=0)
TextureLODGroups=(Group=TEXTUREGROUP_Terrain_Heightmap,MinLODSize=128,MaxLODSize=128,MinMagFilter=point,MipFilter=point,HighPriorityLoad=0,MipGenSettings=TMGS_NoMipmaps,NumStreamedMips=0)
TextureLODGroups=(Group=TEXTUREGROUP_Terrain_Weightmap,MinLODSize=128,MaxLODSize=128,MinMagFilter=point,MipFilter=point,HighPriorityLoad=0,MipGenSettings=TMGS_NoMipmaps,NumStreamedMips=0)
TextureLODGroups=(Group=TEXTUREGROUP_Pixels2D,MinLODSize=1,MaxLODSize=1,MinMagFilter=point,MipFilter=point,HighPriorityLoad=0,MipGenSettings=TMGS_NoMipmaps,NumStreamedMips=0)
TextureLODGroups=(Group=TEXTUREGROUP_Bokeh,MinLODSize=1,MaxLODSize=1,MinMagFilter=point,MipFilter=point,HighPriorityLoad=0,MipGenSettings=TMGS_NoMipmaps,NumStreamedMips=0)
[Core.System]
Paths=../../../Engine/Content
Paths=%GAMEDIR%Content
Paths=../../../Tiger/Plugins/Wwise/Content
Paths=../../../Engine/Plugins/Editor/GeometryMode/Content
Paths=../../../Engine/Plugins/FX/Niagara/Content
Paths=../../../Tiger/Plugins/GMESDK/Content
Paths=../../../Tiger/Plugins/INTLPlugin/Content
Paths=../../../Tiger/Plugins/CentauriSDK/Content
Paths=../../../Engine/Plugins/Experimental/PythonScriptPlugin/Content
Paths=../../../Engine/Plugins/Tests/EditorTests/Content
Paths=../../../Engine/Plugins/Tests/RuntimeTests/Content
Paths=../../../Tiger/Plugins/TSS/Content
Paths=../../../Tiger/Plugins/MTuner-UE4/Content
Paths=../../../Engine/Plugins/Runtime/AMD/FSR2/Content
Paths=../../../Engine/Plugins/Runtime/Nvidia/DLSS/Content
Paths=../../../Engine/Plugins/Runtime/Intel/XeSS/Content
Paths=../../../Tiger/Plugins/EOSSDK/Content
Paths=../../../Tiger/Plugins/ImpostorBaker/Content
Paths=../../../Tiger/Plugins/SentryClientSDK/Content
Paths=../../../Engine/Plugins/2D/Paper2D/Content
Paths=../../../Engine/Plugins/Developer/AnimationSharing/Content
Paths=../../../Engine/Plugins/Editor/SpeedTreeImporter/Content
Paths=../../../Engine/Plugins/Enterprise/DatasmithContent/Content
Paths=../../../Engine/Plugins/Experimental/ChaosClothEditor/Content
Paths=../../../Engine/Plugins/Experimental/GeometryProcessing/Content
Paths=../../../Engine/Plugins/Experimental/GeometryCollectionPlugin/Content
Paths=../../../Engine/Plugins/Experimental/ChaosSolverPlugin/Content
Paths=../../../Engine/Plugins/Experimental/ChaosNiagara/Content
Paths=../../../Engine/Plugins/Experimental/MotoSynth/Content
Paths=../../../Engine/Plugins/MagicLeap/MagicLeapPassableWorld/Content
Paths=../../../Engine/Plugins/Media/MediaCompositing/Content
Paths=../../../Engine/Plugins/Runtime/Synthesis/Content
Paths=../../../Engine/Plugins/Runtime/AudioSynesthesia/Content
[OnlineSubsystem]
NativePlatformService=Steam
[Core.Log]
Global=all off
LogPakFile=all off
LogPlatformFile=all off
LogTaskGraph=all off
LogD3D12RHI=all off
LogICUInternationalization=all off
LogMemory=all off
LogLevelStreaming=all off
LogConfig=all off
LogPluginManager=all off
LogConsoleManager=all off
LogTGameSession=all off
LogBackend=all off
LogBackendReqRsp=all off
LogOnline=all off
LogNetVersion=all off
TigerLogRegionCache=all off
AnimBlueprintLog=all off
PIE=all off
[/Script/Engine.InputSettings]
bViewAccelerationEnabled=False
bEnableMouseSmoothing=False
DoubleClickTime=0.1
ButtonRepeatDelay=0.1
InitialButtonRepeatDelay=0.2
[ConsoleVariables]
r.MaxAnisotropy=2
r.VT.MaxAnisotropy=2
fx.Niagara.QualityLevel=0
fx.NiagaraAllowComputeShaders=1
niagara.CreateShadersOnLoad=1
r.AllowPrecomputedShadows=1
r.CapsuleShadows=0
r.CascadeParticleDetailMode=1
r.DBuffer=0
r.DetailMode=1
r.DistanceFieldAO=0
r.DistanceFieldShadowing=0
r.EarlyZPass=1
r.EmitterSpawnRateScale=0.0625
r.FastVRam.BokehDOF=1
r.FastVRam.CombineLUTs=1
r.FastVRam.DOFPostfilter=1
r.FastVRam.DOFReduce=1
r.FastVRam.DOFSetup=1
r.FastVRam.DistanceFieldAODownsampledBentNormal=1
r.FastVRam.DistanceFieldAOHistory=1
r.FastVRam.DistanceFieldAOScreenGridResources=1
r.FastVRam.DistanceFieldCulledObjectBuffers=1
r.FastVRam.DistanceFieldNormal=1
r.FastVRam.DistanceFieldShadows=1
r.FastVRam.DistanceFieldTileIntersectionResources=1
r.FastVRam.Distortion=1
r.FastVRam.Downsample=1
r.FastVRam.EyeAdaptation=1
r.FastVRam.ForwardLightingCullingResources=1
r.FastVRam.HZB=1
r.FastVRam.Histogram=1
r.FastVRam.HistogramReduce=1
r.FastVRam.LPV=1
r.FastVRam.MotionBlur=1
r.FastVRam.PostProcessMaterial=1
r.FastVRam.SceneColor=1
r.FastVRam.SceneDepth=1
r.FastVRam.ScreenSpaceShadowMask=1
r.FastVRam.ShadowCSM=1
r.FastVRam.ShadowPerObject=1
r.FastVRam.Tonemap=1
r.FastVRam.Upscale=1
r.FastVRam.VelocityFlat=1
r.FastVRam.VelocityMax=1
r.FastVRam.VolumetricFog=1
r.LightFunctionQuality=0
r.LightMaxDrawDistanceScale=0
r.MaterialQualityLevel=0
r.ReflectionCaptureResolution=32
r.RefractionQuality=1
r.ScreenPercentage=90
r.Shaders.BoundsChecking=0
r.Shaders.FastMath=1
r.Shaders.KeepDebugInfo=0
r.Shaders.Optimize=1
r.Shaders.SkipCompression=1
r.Shaders.Validation=0
r.Shaders.ZeroInitialise=0
r.Shadow.CSM.MaxCascades=0
r.Shadow.CSM.TransitionScale=0
r.Shadow.DetailMode=0
r.Shadow.DistanceScale=0
r.Shadow.MaxCSMResolution=0
r.Shadow.MaxResolution=0
r.Shadow.PreShadowResolutionFactor=0
r.Shadow.RadiusThreshold=0
r.ShadowQuality=0
r.ForceLOD=6
r.SkeletalMeshLODBias=1
r.TessellationAdaptivePixelsPerTriangle=2
r.TiledDeferredShading.MinimumCount=32
r.TiledDeferredShading=1
r.UniformBufferPooling=1
r.ViewDistanceScale=0.8
r.StaticMeshLODDistanceScale=0.8
r.chaos.ReflectionCaptureStaticSceneOnly=1
r.SceneColorFormat=1
r.ParticleLightQuality=0
r.RenderTargetPoolMin=1024
r.DistanceFieldBuild.Compress=0
r.AmbientOcclusionLevels=0
r.TranslucencyVolumeBlur=1
r.VertexFoggingForOpaque=0
r.RayTracing=0
r.Shadow.UnbuiltPreviewInGame=1
r.AllowStaticLighting=1
r.NormalMapsForStaticLighting=0
r.GenerateMeshDistanceFields=0
r.DistanceFieldBuild.EightBit=0
r.GenerateLandscapeGIData=0
r.TranslucentSortPolicy=0
TranslucentSortAxis=(X=0.000000,Y=-1.000000,Z=0.000000)
r.SSGI.Enable=0
fx.GPUSimulationTextureSizeX=128
fx.GPUSimulationTextureSizeY=128
r.GBufferFormat=1
r.SkinCache.CompileShaders=0
r.SkinCache.DefaultBehavior=1
r.SkinCache.SceneMemoryLimitInMB=128.000000
r.GPUSkin.Support16BitBoneIndex=0
r.GPUSkin.Limit2BoneInfluences=0
r.GPUSkin.UnlimitedBoneInfluences=0
r.GPUSkin.UnlimitedBoneInfluencesThreshold=8
r.BasePassOutputsVelocity=0
r.VertexDeformationOutputsVelocity=0
r.SelectiveBasePassOutputs=0
r.MinScreenRadiusForLights=0.030000
r.MinScreenRadiusForDepthPrepass=0.030000
r.MinScreenRadiusForCSMDepth=0.010000
; Input-Lag & Frame Pacing CVARS
r.FinishCurrentFrame=1
r.OneFrameThreadLag=1
r.RHICmdBalanceParallelLists=1
r.RHICmdAsyncRHIThreadDispatch=1
r.RHICmdDeferSkeletalLockAndFillToRHIThread=1
r.RHICmdFlushOnQueueParallelSubmit=0
r.RHICmdUseParallelAlgorithms=1
rhi.ResourceTableCaching=1
[ScalabilityGroups]
sg.ResolutionQuality=100.000000
sg.ViewDistanceQuality=3
sg.AntiAliasingQuality=3
sg.ShadowQuality=3
sg.PostProcessQuality=3
sg.TextureQuality=3
sg.EffectsQuality=3
sg.FoliageQuality=3
sg.ShadingQuality=0
[/Script/Engine.GameUserSettings]
bUseVSync=False
bUseDynamicResolution=False
ResolutionSizeX=1920
ResolutionSizeY=1080
LastUserConfirmedResolutionSizeX=1920
LastUserConfirmedResolutionSizeY=1080
WindowPosX=-1
WindowPosY=-1
FullscreenMode=1
LastConfirmedFullscreenMode=1
PreferredFullscreenMode=1
Version=5
AudioQualityLevel=0
LastConfirmedAudioQualityLevel=0
FrameRateLimit=0.000000
DesiredScreenWidth=1280
bUseDesiredScreenHeight=False
DesiredScreenHeight=720
LastUserConfirmedDesiredScreenWidth=1280
LastUserConfirmedDesiredScreenHeight=720
LastRecommendedScreenWidth=-1.000000
LastRecommendedScreenHeight=-1.000000
LastCPUBenchmarkResult=-1.000000
LastGPUBenchmarkResult=-1.000000
LastGPUBenchmarkMultiplier=1.000000
bUseHDRDisplayOutput=False
HDRDisplayOutputNits=1000
[ShaderPipelineCache.CacheFile]
LastOpened=Tiger
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment