openvr_fsr icon indicating copy to clipboard operation
openvr_fsr copied to clipboard

Half-Life: Alyx fails to boot with modified dll file

Open SomeSpicyCheese opened this issue 2 years ago • 16 comments

As the title says, the game fails to boot on my system using the FSR-Enabled openvr_api.dll file, claiming it failed to initialize VR space. RenderScale set to 0.59, all other settings as default.

SomeSpicyCheese avatar Aug 07 '21 13:08 SomeSpicyCheese

Yes, this is known and mentioned in the readme :) No short-term fix, I'm afraid.

fholger avatar Aug 07 '21 13:08 fholger

@fholger it's not about "game doesn't like replacing dll", your DLL simply doesn't have certain functionality. And maybe there actually is a short-term fix:

List of symbols in original DLL:

openvr_api.dll LiquidVR openvr_api.dll VRCompositorSystemInternal openvr_api.dll VRControlPanel openvr_api.dll VRHeadsetView openvr_api.dll VROculusDirect openvr_api.dll VRPaths openvr_api.dll VRRenderModelsInternal openvr_api.dll VRSceneGraph openvr_api.dll VRTrackedCameraInternal openvr_api.dll VRVirtualDisplay openvr_api.dll VR_GetGenericInterface openvr_api.dll VR_GetInitToken openvr_api.dll VR_GetRuntimePath openvr_api.dll VR_GetStringForHmdError openvr_api.dll VR_GetVRInitErrorAsEnglishDescription openvr_api.dll VR_GetVRInitErrorAsSymbol openvr_api.dll VR_InitInternal openvr_api.dll VR_InitInternal2 openvr_api.dll VR_IsHmdPresent openvr_api.dll VR_IsInterfaceVersionValid openvr_api.dll VR_IsRuntimeInstalled openvr_api.dll VR_RuntimePath openvr_api.dll VR_ShutdownInternal

And this is list of symbols in your DLL:

openvr_api.dll VRHeadsetView openvr_api.dll VR_GetGenericInterface openvr_api.dll VR_GetInitToken openvr_api.dll VR_GetRuntimePath openvr_api.dll VR_GetStringForHmdError openvr_api.dll VR_GetVRInitErrorAsEnglishDescription openvr_api.dll VR_GetVRInitErrorAsSymbol openvr_api.dll VR_InitInternal openvr_api.dll VR_InitInternal2 openvr_api.dll VR_IsHmdPresent openvr_api.dll VR_IsInterfaceVersionValid openvr_api.dll VR_IsRuntimeInstalled openvr_api.dll VR_RuntimePath openvr_api.dll VR_ShutdownInternal

I'm not sure but maybe exporting empty placeholder functions may help. If not, every function from original library must be correctly implemented and exported in new library.

romanshuvalov avatar Aug 27 '21 21:08 romanshuvalov

I am aware of that, but these functions are not part of the source code Valve released for OpenVR, so there is no template for these functions. But since they are not part of the released source, they should also not typically be used by games due to not being exposed in the headers. Of course, it's possible Valve uses a custom build or functionality for HL Alyx, but that most definitely rules out the easy fix.

fholger avatar Aug 27 '21 22:08 fholger

I am aware of that, but these functions are not part of the source code Valve released for OpenVR, so there is no template for these functions.

Looking at the assembly code of openvr_api.dll from the game and using the source of openvr_fsr as a template, it is possible to deduce the source code of the missing exported functions.

I loaded C:\Steam\steamapps\common\Half-Life Alyx\game\bin\win64\openvr_api.dll in IDA Freeware and could confirm @romanshuvalov list of missing functions. They all have the same pattern and basically just call VR_GetGenericInterface(). E.g., this is the disassembled LiquidVR function:

                public LiquidVR
LiquidVR        proc near
                sub     rsp, 28h
                mov     rax, cs:m_pLiquidVR
                test    rax, rax
                jnz     short loc_1800012D5
                xor     edx, edx
                lea     rcx, aIliquidvr001 ; "ILiquidVR_001"
                call    VR_GetGenericInterface
                mov     cs:m_pLiquidVR, rax
loc_1800012D5:
                add     rsp, 28h
                retn

This can be translated to C as something like:

    static const char * const ILiquidVR_Version = "ILiquidVR_001";
    public IntPtr m_pLiquidVR;
    void *LiquidVR()
    {
        if ( m_pLiquidVR == nullptr )
        {
            m_pLiquidVR = VR_GetGenericInterface( ILiquidVR_Version, NULL);
        }
        return m_pLiquidVR;
    }

So to recreate these functions it would require declaring the constants, the pointers and the functions:

    static const char * const ILiquidVR_Version = "ILiquidVR_001";
    static const char * const IVRCompositorSystemInternal_Version = "IVRCompositorSystemInternal_001";
    static const char * const IVRControlPanel_Version = "IVRControlPanel_006";
    static const char * const IVROculusDirect_Version = "IVROculusDirect_001";
    static const char * const IVRPaths_Version = "IVRPaths_001";
    static const char * const IVRRenderModelsInternal_Version = "IVRRenderModelsInternal_XXX";
    static const char * const IVRSceneGraph_Version = "IVRSceneGraph_001";
    static const char * const IVRTrackedCameraInternal_Version = "IVRTrackedCameraInternal_001";
    static const char * const IVRVirtualDisplay_Version = "IVRVirtualDisplay_001";

    public IntPtr m_pLiquidVR;
    public IntPtr m_pVRCompositorSystemInternal;
    public IntPtr m_pVRControlPanel;
    public IntPtr m_pVROculusDirect;
    public IntPtr m_pVRPaths;
    public IntPtr m_pVRRenderModelsInternal;
    public IntPtr m_pVRSceneGraph;
    public IntPtr m_pVRTrackedCameraInternal;
    public IntPtr m_pVRVirtualDisplay;

    void *LiquidVR() {
        if ( m_pLiquidVR == nullptr )
            m_pLiquidVR = VR_GetGenericInterface( ILiquidVR_Version, nullptr);
        return m_pLiquidVR;
    }

    void *VRCompositorSystemInternal() {
        if ( m_pVRCompositorSystemInternal == nullptr )
            m_pVRCompositorSystemInternal = VR_GetGenericInterface( IVRCompositorSystemInternal_Version, nullptr);
        return m_pVRCompositorSystemInternal;
    }

    void *VRControlPanel() {
        if ( m_pVRControlPanel == nullptr )
            m_pVRControlPanel = VR_GetGenericInterface( IVRControlPanel_Version, nullptr);
        return m_pVRControlPanel;
    }

    void *VROculusDirect() {
        if ( m_pVROculusDirect == nullptr )
            m_pVROculusDirect = VR_GetGenericInterface( IVROculusDirect_Version, nullptr);
        return m_pVROculusDirect;
    }

    void *VRPaths() {
        if ( m_pVRPaths == nullptr )
            m_pVRPaths = VR_GetGenericInterface( IVRPaths_Version, nullptr);
        return m_pVRPaths;
    }

    void *VRRenderModelsInternal() {
        if ( m_pVRRenderModelsInternal == nullptr )
            m_pVRRenderModelsInternal = VR_GetGenericInterface( IVRRenderModelsInternal_Version, nullptr);
        return m_pVRRenderModelsInternal;
    }

    void *VRSceneGraph() {
        if ( m_pVRSceneGraph == nullptr )
            m_pVRSceneGraph = VR_GetGenericInterface( IVRSceneGraph_Version, nullptr);
        return m_pVRSceneGraph;
    }

    void *VRTrackedCameraInternal() {
        if ( m_pVRTrackedCameraInternal == nullptr )
            m_pVRTrackedCameraInternal = VR_GetGenericInterface( IVRTrackedCameraInternal_Version, nullptr);
        return m_pVRTrackedCameraInternal;
    }

    void *VRVirtualDisplay() {
        if ( m_pVRVirtualDisplay == nullptr )
            m_pVRVirtualDisplay = VR_GetGenericInterface( IVRVirtualDisplay_Version, nullptr);
        return m_pVRVirtualDisplay;
    }

Also, the pointers must be cleared (set to nullptr) at the end of VR_ShutdownInternal:

    m_pLiquidVR = nullptr;
    m_pVRCompositorSystemInternal = nullptr;
    m_pVRControlPanel = nullptr;
    m_pVROculusDirect = nullptr;
    m_pVRPaths = nullptr;
    m_pVRRenderModelsInternal = nullptr;
    m_pVRSceneGraph = nullptr;
    m_pVRTrackedCameraInternal = nullptr;
    m_pVRVirtualDisplay = nullptr;

Will these changes make openvr_fsr work with Half-Life: Alyx? I have no idea, but it might be worth giving it a try.

AltoRetrato avatar Dec 05 '21 23:12 AltoRetrato

Progress report summary: I added the missing functions, they don't seem to be called but the code runs further along anyway. An access violation in IVRSystem_GetRecommendedRenderTargetSize() crashes the game.

Starting Half-Life: Alyx with unpatched openvr_api.dll v. 2.0:

  1. Shows a pop-up "Unable to Start Game" - "A game file appears to be missing or corrupted. In the Steam client go to the game's properties. In the 'Local Files' tab select 'Verify Integrity of Game Cache' to have Steam double-check the game's installation."
  2. Shows a pop-up "Error" - "CAppSystemDict::LoadSystemAndDependencies(): CAppSystemDict:Unable to load module vr (Dependency of application), error 127"
  3. Steam automatically downloads the game original openvr_api.dll.
  4. No openvr_mod.log is created.
  5. The game crashes and saves a minidump. Among other details, the minidump contains:
VR NOT ENABLED
Launch path: C:\Steam\steamapps\common\Half-Life Alyx\game\bin\win64\hlvr.exe
g_pRenderDeviceMgr is NULL. Driver data unavailable

Console History (reversed)

8(227.976031):  CAppSystemDict:Unable to load module vr (Dependency of application), error 127

7(0.325067):  Sending Steam API content notification
6(0.324831):  WARNING: Local content might be corrupt or missing files
5(0.319209):  SteamVR initialization begin...
4(0.212197):  CSteam3Client::Activate succeeded.  SteamID is [U:1:xxxxxxxx] (xxxxxxxxxxxxxxxxx), AppID is 546560
3(0.207766):  SteamAPI_Init succeeded.  SteamID is [U:1:xxxxxxxx] (xxxxxxxxxxxxxxxxx), AppID is 546560
2(0.055898):  Steam AppId(546560)
1(0.053951):  Unable to read steam.inf from hlvr!

I patched openvr_api_public.cpp, including empty functions and some calls to Log() the functions being called, e.g.:

VR_EXPORT_INTERFACE void *VR_CALLTYPE LiquidVR();
void *LiquidVR() {
	Log() << "TRACE: [openvr_api_public.cpp] LiquidVR()\n";
    return nullptr;
}

With this new DLL the game still won't start, but:

  1. There are no pop-up errors, and the DLL is not replaced by Steam.
  2. Minidump show progress, including a message with "Recommended render target size":
SteamVR Version: 1.20.4
SteamVR HMD:    (0Hz)

Launch path: C:\Steam\steamapps\common\Half-Life Alyx\game\bin\win64\hlvr.exe
g_pRenderDeviceMgr is NULL. Driver data unavailable

Console History (reversed)

6(0.839426):  Recommended render target size: 424 x 428
5(0.324118):  SteamVR initialization begin...
4(0.212707):  CSteam3Client::Activate succeeded.  SteamID is [U:1:xxxxxxxx] (xxxxxxxxxxxxxxxxx), AppID is 546560
3(0.209934):  SteamAPI_Init succeeded.  SteamID is [U:1:xxxxxxxx] (xxxxxxxxxxxxxxxxx), AppID is 546560
2(0.054402):  Steam AppId(546560)
1(0.052336):  Unable to read steam.inf from hlvr!
  1. openvr_mod.log is created, with:
TRACE: [openvr_api_public.cpp] VR_GetGenericInterface()
TRACE: [openvr_api_public.cpp] VR_InitInternal2()
Initializing hooks...
TRACE: [openvr_api_public.cpp] VR_LoadHmdSystemInternal()
TRACE: [openvr_api_public.cpp] VR_IsInterfaceVersionValid()
TRACE: [openvr_api_public.cpp] VR_GetInitToken()
TRACE: [openvr_api_public.cpp] VR_GetGenericInterface()
Requested interface IVRSystem_021
Injecting GetRecommendedRenderTargetSize into IVRSystem_021

Analyzing the exception in the minidump:

ExceptionAddress: 00007fff4d5dd852 (openvr_api!`anonymous namespace'::IVRSystem_GetRecommendedRenderTargetSize+0x0000000000000082)
   ExceptionCode: c0000005 (Access violation)
  ExceptionFlags: 00000000
NumberParameters: 2
   Parameter[0]: 0000000000000001
   Parameter[1]: 00007fff4d81a7e8
Attempt to write to address 00007fff4d81a7e8

ERROR_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%p referenced memory at 0x%p. The memory could not be %s.

FAULTING_LOCAL_VARIABLE_NAME:  pnWidth

STACK_TEXT:  
00000024`88ccf5d0 00007fff`4d738f3b     : 00007fff`43f6ab98 00007fff`4d81a7e8 00007fff`4d849dc8 00007fff`4d81bb20 : openvr_api!`anonymous namespace'::IVRSystem_GetRecommendedRenderTargetSize+0x82
00000024`88ccf600 00007fff`3d1118ac     : 000001dc`00000000 00000000`ff00ff00 000001dc`c7fe0700 00007fff`3d47f458 : vr+0x8f3b
00000024`88ccf800 00007fff`3d15b99a     : 00000000`ff00ff00 00000000`00000000 00000000`00000000 00007fff`46f1770d : engine2+0x1018ac
00000024`88ccf8d0 00007fff`3d15f638     : 00007ff6`73680000 00000000`00000000 00000000`0000000a 00007fff`3d490700 : engine2+0x14b99a
00000024`88ccf970 00007ff6`73681313     : 00000000`0000000a 00000000`00000000 000001dc`c52c6213 00000000`00000000 : engine2!Source2Main+0x1c8
00000024`88ccfa00 00007ff6`736815f7     : 00000000`0000000a 00000000`00000000 00000000`00000000 00000000`00000000 : hlvr+0x1313
00000024`88ccfb50 00007fff`c7cd7034     : 00000000`00000000 00000000`00000000 00000000`00000000 00007fff`5b4b0000 : hlvr+0x15f7
00000024`88ccfb90 00007fff`c8542651     : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : kernel32!BaseThreadInitThunk+0x14
00000024`88ccfbc0 00000000`00000000     : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x21

FAULTING_SOURCE_LINE:  C:\Steam\steamapps\common\!openvr_fsr_v2.0\openvr_fsr-fsr_v2.0\src\postprocess\VrHooks.cpp

FAULTING_SOURCE_CODE:  
    44: 		if (Config::Instance().fsrEnabled && Config::Instance().renderScale < 1) {
>   45: 			*pnWidth *= Config::Instance().renderScale;
    46: 			*pnHeight *= Config::Instance().renderScale;
    47: 		}

So I patched IVRSystem_GetRecommendedRenderTargetSize():

if (Config::Instance().fsrEnabled && Config::Instance().renderScale < 1) {
    Log() << "TRACE: IVRSystem_GetRecommendedRenderTargetSize()\n";
    Log() << "pnWidth: " << pnWidth << ", *pnWidth: " << *pnWidth << ", Config::Instance().renderScale: " << Config::Instance().renderScale << std::endl;
    Log() << "pnHeight: " << pnHeight << ", *pnHeight: " << *pnHeight << std::endl;
    *pnWidth *= Config::Instance().renderScale;
    *pnHeight *= Config::Instance().renderScale;
}

... and the new openvr_mod.log has:

TRACE: [openvr_api_public.cpp] VR_GetGenericInterface()
TRACE: [openvr_api_public.cpp] VR_InitInternal2()
Initializing hooks...
TRACE: [openvr_api_public.cpp] VR_LoadHmdSystemInternal()
TRACE: [openvr_api_public.cpp] VR_IsInterfaceVersionValid()
TRACE: [openvr_api_public.cpp] VR_GetInitToken()
TRACE: [openvr_api_public.cpp] VR_GetGenericInterface()
Requested interface IVRSystem_021
Injecting GetRecommendedRenderTargetSize into IVRSystem_021
TRACE: [openvr_api_public.cpp] VR_GetGenericInterface()
Requested interface IVRSystem_021
TRACE: IVRSystem_GetRecommendedRenderTargetSize()
pnWidth: 00007FFF4DE19140, *pnWidth: 2124, Config::Instance().renderScale: 0.2
pnHeight: 00007FFF4DE19144, *pnHeight: 2144
TRACE: [openvr_api_public.cpp] VR_GetGenericInterface()
Requested interface IVRApplications_007
TRACE: [openvr_api_public.cpp] VR_GetGenericInterface()
Requested interface IVROverlay_024
TRACE: IVRSystem_GetRecommendedRenderTargetSize()
pnWidth: 00007FFF4DDEA7E8, *pnWidth: 1953724787, Config::Instance().renderScale: 0.2
pnHeight: 00007FFF4DE19DC8, *pnHeight: 0

FWIW, the DLL works in another game without issues (Blade Runner 9732).

Sorry about the long post.

Any ideas?

AltoRetrato avatar Dec 13 '21 19:12 AltoRetrato

There has to be a better way to do this, but I got the game to start by adding this to IVRSystem_GetRecommendedRenderTargetSize():

Log() << "TRACE: IVRSystem_GetRecommendedRenderTargetSize()\n";
Log() << "pnWidth: " << pnWidth << std::endl;
Log() << "pnHeight: " << pnHeight << std::endl;
if (pnWidth == reinterpret_cast<uint32_t*>(0x000000003FF00000)) {
	Log() << "INVALID POINTER (address)" << std::endl;
	return;
}
if (*pnWidth == 0 || *pnHeight == 0) {
	Log() << "INVALID POINTER (== 0)" << std::endl;
	return;
}
Log() << "*pnWidth: " << *pnWidth << std::endl;
Log() << "*pnHeight: " << *pnHeight << std::endl;

With resulting openvr_mod.log:

Initializing hooks...
Requested interface IVRSystem_021
Injecting GetRecommendedRenderTargetSize into IVRSystem_021
Requested interface IVRSystem_021
TRACE: IVRSystem_GetRecommendedRenderTargetSize()
pnWidth: 00007FFAEF5E9140
pnHeight: 00007FFAEF5E9144
*pnWidth: 2204
*pnHeight: 2236
Requested interface IVRApplications_007
Requested interface IVROverlay_024
TRACE: IVRSystem_GetRecommendedRenderTargetSize()
pnWidth: 00007FFAEF5BA7E8
pnHeight: 00007FFAEF5E9DC8
INVALID POINTER (== 0)
Requested interface IXrProto_001
Requested interface IVRInput_010
Requested interface IVROverlayView_003
Requested interface IVRInputInternal_002
Requested interface IVRMailbox_001
Requested interface IVRChaperone_003
Requested interface IVRCompositor_026
Injecting Submit into IVRCompositor_026
Requested interface IVRRenderModels_006
TRACE: IVRSystem_GetRecommendedRenderTargetSize()
pnWidth: 000000003FF00000
pnHeight: 00000000FFFFFFFF
INVALID POINTER (address)
Requested interface IVRControlPanel_006
Creating post-processing resources
Input texture is in SRGB color space
Creating output textures in format 28
Using AMD FidelityFX SuperResolution
Requested interface IVRSystem_022
Raw projection for eye 0: l -1.27994, r 1, t -1.19175, b 1.11061
Display is canted by 0 RAD
Projection center for eye 0: 0.561392, 0.517621
Requested interface IVRSystem_022
Raw projection for eye 1: l -1, r 1.27994, t -1.19175, b 1.11061
Display is canted by -0 RAD
Projection center for eye 1: 0.438608, 0.517621
Creating upscaled texture of size 5425x2750
Requested interface IVRSystem_022
Raw projection for eye 0: l -1.27994, r 1, t -1.19175, b 1.11061
Display is canted by 0 RAD
Projection center for eye 0: 0.561392, 0.517621
Requested interface IVRSystem_022
Raw projection for eye 1: l -1, r 1.27994, t -1.19175, b 1.11061
Display is canted by -0 RAD
Projection center for eye 1: 0.438608, 0.517621
Creating sharpened texture of size 5425x2750
Injecting PSSetSamplers into D3D11DeviceContext
Creating replacement sampler for 000002669387A1E0 with MIP LOD bias -0.376811
Creating replacement sampler for 00000266938786E0 with MIP LOD bias -0.376811
Creating replacement sampler for 0000026693879FA0 with MIP LOD bias -0.376811
Creating replacement sampler for 0000026693879C20 with MIP LOD bias -0.376811
Creating replacement sampler for 000002662E658220 with MIP LOD bias -0.376811
Creating replacement sampler for 000002669378C2A0 with MIP LOD bias -0.376811
Creating replacement sampler for 0000026693879460 with MIP LOD bias -0.376811
Creating replacement sampler for 000002669387A420 with MIP LOD bias -0.376811
Creating replacement sampler for 0000026693878DA0 with MIP LOD bias -0.376811
Creating replacement sampler for 0000000000000000 with MIP LOD bias -0.376811
Creating shader resource view for input texture 00000265D7037C38
Texture has size 4178x2118 and format 27
Creating replacement sampler for 000002662E657A20 with MIP LOD bias -0.376811
Creating replacement sampler for 00000266938796A0 with MIP LOD bias -0.376811
Creating replacement sampler for 0000026693878B60 with MIP LOD bias -0.376811
Creating replacement sampler for 000002669387A2E0 with MIP LOD bias -0.376811
Creating replacement sampler for 000002669378B520 with MIP LOD bias -0.376811
Creating replacement sampler for 000002669378B1E0 with MIP LOD bias -0.376811
Creating replacement sampler for 00000266151492A0 with MIP LOD bias -0.376811
Creating replacement sampler for 0000026693879B20 with MIP LOD bias -0.376811

Edit: Found a better way using IsBadMemPtr from https://gist.github.com/arbv/531040b8036050c5648fc55471d50352

if (IsBadMemPtr(TRUE, pnWidth, sizeof(pnWidth)) || IsBadMemPtr(TRUE, pnHeight, sizeof(pnHeight))) {
	Log() << "INVALID POINTER (IsBadMemPtr)" << std::endl;
	return;
}

skrimix avatar Dec 14 '21 11:12 skrimix

Confirmed working on the menu.

OculusScreenshot1639487865

But when I load a saved game:

Clipboard01

AltoRetrato avatar Dec 14 '21 13:12 AltoRetrato

Seems to load fine for me. 20211214184054_1_vr Not sure what's up with misplaced "sweet spot", I haven't used this mod before.

Edit: I remembered that I got the same Timed out error when tried my older approach (DLL proxy/redirection) after fixing Access violation. Although, it crashed even before menu. Also I wasn't sure on how to export missing functions so I was changing stuff semi-randomly. Perhaps I did something differently? Here's my diff: https://gist.github.com/skrimix/c38311227c26ce703d530d362bb3a4bc

skrimix avatar Dec 14 '21 13:12 skrimix

Alyx has dynamic resolution scaling, so depending on the current scene and performance headroom, it may only render to a part of the texture. But the mod isn't aware and will always place the sweet spot as if the whole texture had been rendered to. That's why it's mismatched. Properly supporting this would require some refactoring; given how well Alyx performs compared to most other VR games, I'm not sure it's really worth the effort.

Kudos on getting it to work, though. :)

fholger avatar Dec 14 '21 17:12 fholger

Using just dummy functions (returning nullptr) didn't make the game load, but using the code as I posted originally, it load and play fine. From a quick test, the GPU load decrease was quite significant.

My guess is that this patch could also make FSR work in other games as well.

@fholger , would you be interested in adding this patch to your code? If you prefer a pull request, let us know.

And BTW, thanks for your work on openvr_fsr! 😄

AltoRetrato avatar Dec 14 '21 17:12 AltoRetrato

Depends. I have no issue adding a bunch of function stubs, but I would be a bit more sceptical of some of the hacks that have been discussed in this thread :) A pull request ist definitely the best route to go, though.

fholger avatar Dec 16 '21 09:12 fholger

I would be a bit more sceptical of some of the hacks that have been discussed in this thread :)

I wonder is there is a better solution than IsBadMemPtr in IVRSystem_GetRecommendedRenderTargetSize to detect an invalid pointer... or if there is any way to avoid the function being called with bad parameters.

A pull request ist definitely the best route to go, though.

Done.

AltoRetrato avatar Dec 16 '21 14:12 AltoRetrato

Since this patch is probably not yet final, if anyone wants to give it a try you can get the patched DLL here and see how well (or not) it works in Half-Life: Alyx for you.

AltoRetrato avatar Dec 16 '21 18:12 AltoRetrato

Alyx has dynamic resolution scaling, so depending on the current scene and performance headroom, it may only render to a part of the texture. But the mod isn't aware and will always place the sweet spot as if the whole texture had been rendered to. That's why it's mismatched. Properly supporting this would require some refactoring; given how well Alyx performs compared to most other VR games, I'm not sure it's really worth the effort.

Kudos on getting it to work, though. :)

You can close dynamic resolution scaling with (-console -vconsole +vr_fidelity_level_auto 0 +vr_fidelity_level 6) I guess level 6 for the most ideal resolution %151 - 2689x2988. When dynamic resolution working on medium tier computers, fidelity lvl is around lvl3 in most scenes, which is very annoying. If this works, it could offer a much better quality experience. Maybe it's worth it :))

turuncux avatar Dec 22 '21 13:12 turuncux

Alyx has dynamic resolution scaling, so depending on the current scene and performance headroom, it may only render to a part of the texture. But the mod isn't aware and will always place the sweet spot as if the whole texture had been rendered to. That's why it's mismatched. Properly supporting this would require some refactoring; given how well Alyx performs compared to most other VR games, I'm not sure it's really worth the effort.

Kudos on getting it to work, though. :)

You can disable dynamic resolution scaling in the launch options: Level 3 is 100%, and it's what I use.

Crimson-foxGITHUB avatar Apr 11 '22 23:04 Crimson-foxGITHUB

Game doesn't start anymore?

arczi84 avatar Nov 27 '22 20:11 arczi84