catsethecat / vrmod-module

openvr module for garry's mod
zlib License
122 stars 32 forks source link

"Visual glitches such as stretched or cut off views, skybox glitches, left eye is gray, etc:" #1

Open willox opened 4 years ago

willox commented 4 years ago

Could be caused by race conditions between the d3d9 and d3d11 contexts? I don't see any synchronisation between the two for accessing your shared textures.

Each direct3d context can queue commands to the GPU rather than executing them straight away and the game itself can queue d3d9 API calls, so to fix it you'd have to do a couple of things:

1) Flush Source's render context before submitting your eyes and then wait for the d3d9 context to have executed those calls on the GPU. 2) Make sure your d3d11 context has also finished executing its queued commands before you let the game render to the shared texture again.

These examples aren't fully tested, but they are a bit. Hopefully it'll explain what I think is going on.

// d3d9 synch
static void VR_PreSubmit()
{
    IMatRenderContext *pRenderContext = materials; // you can probably figure this bit out
    pRenderContext->BeginRender();
    pRenderContext->Flush( true );
    pRenderContext->EndRender();

    IDirect3DQuery9* pEventQuery = nullptr;
    d3d9Device->CreateQuery( D3DQUERYTYPE_EVENT, &pEventQuery );

    if ( pEventQuery != nullptr )
    {
        pEventQuery->Issue( D3DISSUE_END );
        while ( pEventQuery->GetData( nullptr, 0, D3DGETDATA_FLUSH ) != S_OK );
        pEventQuery->Release(); 
    }
}

// you could draw this out into two functions (and call them at more ideal points of the frame) like the d3d11 example if you wanted to avoid locking where possible
// d3d11 synch
static ID3D11Query* s_pCurrentQuery = nullptr;

static void VR_PreRender()
{
    if ( !s_pCurrentQuery )
        return;

    while ( d3d11context->GetData( s_pCurrentQuery, NULL, 0, 0 ) == S_FALSE )
    {}

    s_pCurrentQuery->Release();
    s_pCurrentQuery = nullptr;
}

static void VR_PostRender()
{
    D3D11_QUERY_DESC queryDesc;
    queryDesc.MiscFlags = 0;
    queryDesc.Query = D3D11_QUERY_EVENT;

    d3d11device->CreateQuery( &queryDesc, &s_pCurrentQuery );

    d3d11context->Flush();
    d3d11context->End( s_pCurrentQuery );
}

Although you'd still need to do a little more work for this to work properly with multi-core rendering. I don't really want to complicate this issue further.

catsethecat commented 4 years ago

I think that's unrelated to the issues mentioned in the title. Those are caused by the way I'm rendering the game to a high res RT in the addon when that option is checked. It happens in vanilla gmod when doing the following:

local rtwidth, rtheight = ScrW()*1.5, ScrH()*1.5
local rt = GetRenderTarget( "asdf", rtwidth, rtheight )

hook.Add( "RenderScene", "asdf", function()
    render.PushRenderTarget( rt )
    render.RenderView( { x = 0, y = 0, w = rtwidth/2, h = rtheight } )
    render.RenderView( { x = rtwidth/2, y = 0, w = rtwidth/2, h = rtheight } )
    render.PopRenderTarget()
    render.DrawTextureToScreen( rt )
    return true
end )

Result: 20200227113017_1 20200227112755_1

Maybe there is a better way to do it that I'm unaware of?

The d3d synchronization might be the cause of another problem, there are cases where the view jitters and it looks like frames are submitted out of order. It always happens when gmod_mcore_test is enabled and its possible to get it to happen even with it off. I've been able to do it by putting my GPU under heavy load in gmod (>90%) while in VR. I don't have any prior experience with d3d so I didn't even know that was a thing lol.

willox commented 4 years ago

Oh right, I have some patches I could apply to GMod to fix that. I tried some VR code similar to this before so I've been through the same problems.

In my case I only ever played at my headset's native resolution and used separate textures for the eyes, so frequently would see only one eye rendered.

willox commented 4 years ago

As for multicore rendering, it's just a matter of placing some of your calls into GMod's threaded render queue. I will look into providing more of my code or creating a PR.

willox commented 4 years ago

I've fixed the issue you mentioned on GMod's dev, chromium, and x86-64 branches.

image

catsethecat commented 4 years ago

Thanks, much appreciated! I tested it again and it indeed seems to be working properly now.

catsethecat commented 4 years ago

I was able to run tests with all of the code you provided (Source render context flush, d3d9 sync and d3d11 sync) and it looks like the d3d9 sync was enough to fix the other issue I was having (some visual glitches under heavy GPU load even with mcore off) so I've included it in the latest version.

The only remaining issue seems to be multi-core rendering. I found out that if I included the d3d11 sync I could enable mcore and get no visual artifacts, but the view started lagging behind head movements which is quite weird.