1

So I am attempting to write a multi window co-op game using directx12. (each player has their own window to allow no screen cheating if they have multiple monitors). But I am having trouble with dealing with VSync when presenting the swapchains for each player window.

How do I properly handle VSync so that presenting the windows don't cause a massive frame drop due to V-Sync?

Here is the rough outline of what I am doing:

uint32_t dwNumPlayers = 4;

sRENDERER.WindowClass.cbSize = sizeof( WNDCLASSEX );
sRENDERER.WindowClass.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
sRENDERER.WindowClass.lpfnWndProc = Win32MainWindowCallback;
sRENDERER.WindowClass.cbClsExtra = 0;
sRENDERER.WindowClass.cbWndExtra = 0;
sRENDERER.WindowClass.hInstance = GetModuleHandle( NULL );
sRENDERER.WindowClass.hIcon = LoadIcon( 0, IDI_APPLICATION ); 
sRENDERER.WindowClass.hCursor = LoadCursor( 0, IDC_ARROW ); /
sRENDERER.WindowClass.hbrBackground = NULL; 
sRENDERER.WindowClass.lpszMenuName = NULL;   
sRENDERER.WindowClass.lpszClassName = "PlayerWindowClass"; 
sRENDERER.WindowClass.hIconSm = NULL; 

if ( !RegisterClassEx( &sRENDERER.WindowClass ) )
{
    logWindowsError( "Failed to Register Window Class:\n" );
    return -1;
}

//... init directx and get a direct command queue and create all the win32 windows

uint32_t dwStartingWindowWidth = 600;
uint32_t dwStartingWindowHeight = 450;


HWND WindowHandles[MAX_NUM_PLAYERS];
IDXGISwapChain4* swapChain[MAX_NUM_PLAYERS];

for( uint32_t dwPlayer = 0; dwPlayer < dwNumPlayers; ++dwPlayer )
{
    char buf[64];
    sprintf_s( &buf[0], 64, "Player: %u", dwPlayer + 1 );


    WindowHandles[dwPlayer] = CreateWindowEx( 0, sRENDERER.WindowClass.lpszClassName, buf,
        WS_OVERLAPPEDWINDOW | WS_VISIBLE,  CW_USEDEFAULT, CW_USEDEFAULT, dwStartingWindowWidth , dwStartingWindowHeight, 
        0, 0, sRENDERER.WindowClass.hInstance, NULL );
    if ( !sRENDERER.WindowHandles[dwPlayer] )
    {
        logWindowsError( "Failed to Instantiate Window Class:\n" ); 
        return -1;
    }


    DXGI_SWAP_CHAIN_DESC1 swapChainDesc;
    swapChainDesc.Width = dwStartingWindowWidth;
    swapChainDesc.Height = dwStartingWindowHeight;
    swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    swapChainDesc.Stereo = 0;
    swapChainDesc.SampleDesc.Count = 1;
    swapChainDesc.SampleDesc.Quality = 0;
    swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    swapChainDesc.BufferCount = 3;
    swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
    swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
    swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
    swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
    
    IDXGISwapChain1* tempSwapChain = NULL;
    if( FAILED( sRENDERER.dxgiFactory->CreateSwapChainForHwnd( sRENDERER.gfxCommandQueue, WindowHandles[dwPlayer], &swapChainDesc, NULL, NULL, &tempSwapChain  ) ) )
    {
        logError( "Failed to create swap chain!\n" ); 
        return false;
    }

    if( FAILED( tempSwapChain->QueryInterface( IID_PPV_ARGS( &swapChain[dwPlayer] ) ) ) )
    {
        logError( "Failed to query swap chain interface!\n" ); 
        return false;
    }
    tempSwapChain->Release();



    //setup rtv's


}


while(bRunning)
{
    //... render
    
    sRENDERER.gfxCommandQueue->ExecuteCommandLists( dwNumPlayers, sRENDERER.gfxCommandList[dwFrame] ); 
    SignalCurrentFrame();
    

    //uint32_t syncInterval = 1; 
    //uint32_t presentFlags = 0;
    uint32_t syncInterval = 0; //turning off vsync, but how to handle with VSync on?
    uint32_t presentFlags = DXGI_PRESENT_ALLOW_TEARING; //can i do this without tearing?
    for( uint32_t dwPlayer = 0; dwPlayer < dwNumPlayers; ++dwPlayer )
    {
        if( FAILED( swapChain[dwPlayer]->Present( syncInterval, presentFlags ) ) )
        {
            logError( "Error presenting swap chain buffer!\n" ); 
            break;
        }
    }
}

These are my sources:

  1. https://learn.microsoft.com/en-us/windows/win32/direct3ddxgi/dxgi-multiple-swap-chains
  2. Fast multi-window rendering
  3. DirectX VSYNC inaccuracy
  4. Synchronizing multiple OpenGL windows to vsync
  5. Multiple OpenGL contexts, multiple windows, multithreading, and vsync
yosmo78
  • 489
  • 4
  • 13
  • Only the first link (https://learn.microsoft.com/en-us/windows/win32/direct3ddxgi/dxgi-multiple-swap-chains) and also https://learn.microsoft.com/en-us/windows/win32/direct3ddxgi/for-best-performance--use-dxgi-flip-model are relevant. The other are either non-windows oriented and useless (they don't know the DWM exists) or legacy. The first link is really the way to go. Do you face a real problem (in this case, please give a complete full repro code, not just a piece of "something") or is it just a rhetoric question? – Simon Mourier Aug 02 '23 at 15:15

0 Answers0