ValveSoftware / openvr

OpenVR SDK
http://steamvr.com
BSD 3-Clause "New" or "Revised" License
6.03k stars 1.27k forks source link

Why i get wrong texture from IVRVirtualDisplay? #1732

Open fww0071215 opened 1 year ago

fww0071215 commented 1 year ago

I use IVRVirtualDisplay to get texture from OpenVR and use D3D11 API to display it on my own win32window. My driver works as follows: I implement both IVRDisplayComponent and IVRVirtualDisplay,and i return the two components in ITrackedDeviceServerDriver::GetComponent. my code in IVRVirtualDisplay::Present is:

    //Check and create win32 window
    static bool isInitWindow = false;
    if (false == isInitWindow)
    {
        isInitWindow = true;
        InitWindow();
    }
    //msg proc
    MSG msg = {};
    while (PeekMessage(&msg, m_hwnd, 0, 0, PM_REMOVE))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    //get texture
    ID3D11Texture2D* pTexture = nullptr;;
    //check cache
    for (SharedTextures_t::iterator it = m_SharedTextureCache.begin();
        it != m_SharedTextureCache.end(); ++it)
    {
        if (it->m_hSharedTexture == (HANDLE)pPresentInfo->backbufferTextureHandle)
        {
            pTexture = it->m_pTexture;
        }
    }
    //if cache miss open resource
    if (nullptr == pTexture)
    {
        if (SUCCEEDED(m_d3dDevice->OpenSharedResource((HANDLE)pPresentInfo->backbufferTextureHandle, __uuidof(ID3D11Texture2D), (void**)&pTexture)))
        {
            SharedTextureEntry_t entry{ (HANDLE)pPresentInfo->backbufferTextureHandle, pTexture };
            m_SharedTextureCache.push_back(entry);
        } 
    }
    //for debug
    if (pTexture == NULL)
    {
        MessageBox(nullptr, L"pTexture", L"pTexture", 0);
    }
    else
    {
        //get mutex
        IDXGIKeyedMutex* pKeyedMutex = NULL;
        if (SUCCEEDED(pTexture->QueryInterface(__uuidof(IDXGIKeyedMutex), (void**)&pKeyedMutex)))
        {
            if (pKeyedMutex->AcquireSync(0, 10) != S_OK)
            {
                pKeyedMutex->Release();
                return;
            }
            D3D11_TEXTURE2D_DESC srcDesc;
            pTexture->GetDesc(&srcDesc);
            //copy texture to backbuffer
            ID3D11Texture2D* pBuffer;
            if (SUCCEEDED(m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&pBuffer)))
            {
                m_d3dContext->CopyResource(pBuffer, pTexture);
            }
            pKeyedMutex->ReleaseSync(0);
            pKeyedMutex->Release();
            //show
            m_swapChain->Present(0, 0);
        }
    }

my code works well but some times i get some unexpected texture, the black edge seems moved, the first image is normal texture, the second image is the unexpected texture.

compare

This phenomenon is highly likely to occur when the frame rate fluctuates and I am rotating the HMD, which will cause the screen of the HMD to flicker, with black blocks flashing at the edge of the field of view. Can someone help me solve this problem?thanks.

Rectus commented 1 year ago

That sounds like it could be normal reprojection behavior. The compositor will reproject each frame by predicting from the latest received poses, and the more the pose differs from the pose the application rendered the frame with, the larger the gap will be. Usually the area should be small enough that it's not visible through the HMD lens.

If you are making a custom HMD, it might be a good idea to make sure that you are providing correct pose and timing data, as well as updating the poses at a high enough frequency, so that the runtime can make good pose predictions. If the entire display is visible though the lens it might also be necessary to make the field of view larger, and crop out part of the texture.