RobertBeckebans / RBDOOM-3-BFG

Doom 3 BFG Edition source port with updated DX12 / Vulkan renderer and modern game engine features
https://www.moddb.com/mods/rbdoom-3-bfg
GNU General Public License v3.0
1.37k stars 244 forks source link

Unable to initialize OpenGL, render device is null #844

Open jfmherokiller opened 4 months ago

jfmherokiller commented 4 months ago

I started documenting this on discord but It seems that on my system the game will not start regardless if i choose vulkan or dx12.

under my system it seems that the function void idRenderProgManager::Init( nvrhi::IDevice* device ) is passed a nullptr.

system info: image

error observed in visual studio using current master commit f9f256c29c849040f093ed147c5a86a0532e863e

image

RobertBeckebans commented 4 months ago

It is good that you got it compiled so we can figure it out together why it fails. The issue is not really that nullptr is passed into void idRenderProgManager::Init( nvrhi::IDevice* device ); It is that the device creation fails and returns null all the time. You need to track the issue in neo/sys/DeviceManager_DX12.cpp Make a breakpoint before the device creation begins and step into it.

2023-12-29 12_03_09-Clipboard

It would be great if you can figure out why the creation of DeviceManager_DX12::m_NvrhiDevice fails.

jfmherokiller commented 4 months ago

well devicemanager is not null where the null seems to come into play is when deviceManager->GetDevice() is called. But I am rn debugging why the creation seems to fail.

So far the only thing i can come up with is that CreateDeviceAndSwapChain is not being called.

Which in turn means that this line

    m_NvrhiDevice = nvrhi::d3d12::createDevice( deviceDesc );

is never called

jfmherokiller commented 4 months ago

tried this idea

    deviceManager = DeviceManager::Create( api );
    deviceManager->CreateWindowDeviceAndSwapChain();

which seemed to make it want to behave for a short bit

tho i think it fails here

hr = pDxgiFactory->CreateSwapChainForHwnd( m_GraphicsQueue, ( HWND )windowHandle, &m_SwapChainDesc, &m_FullScreenDesc, nullptr, &pSwapChain1 );
SRSaunders commented 4 months ago

Quick question: does your console log report "Unable to initialize OpenGL" on failure/exit? If so, this typically means the game cannot find a working display resolution or video mode for the display you have selected. This would also align with your theory that swap chain creation is failing.

Are you starting up in windowed mode or fullscreen mode? You could try forcing windowed mode by setting r_fullscreen -1 in your D3BFGConfig.cfg file or autoexec.cfg file. I have also seen startup failures when trying to start up on multi-display setups where the window is trying to open on a display which is not turned on, and fails. There is detection logic in the startup code which tries to avoid this problem, but there may be edge cases still. If you see the console message: "WARNING: Window position out of bounds, falling back to primary display" something like this may be happening and the code is trying to recover by forcing the window back to your primary monitor.

One other possibility - I notice you have multiple graphics adaptors. Which one is being used for the game? Your 1050 has only 2GB of graphics memory which may be insufficient for supporting both your desktop and the game (which takes 1-2GB of graphics memory on its own, depending on window resolution). For DX12, you can force the game to use your 2080 (4 GB) by setting r_graphicsAdapter 2080in your autoexec.cfg file.

jfmherokiller commented 4 months ago

Quick question: does your console log report "Unable to initialize OpenGL" on failure/exit? If so, this typically means the game cannot find a working display resolution or video mode for the display you have selected. This would also align with your theory that swap chain creation is failing.

Are you starting up in windowed mode or fullscreen mode? You could try forcing windowed mode by setting r_fullscreen -1 in your D3BFGConfig.cfg file or autoexec.cfg file. I have also seen startup failures when trying to start up on multi-display setups where the window is trying to open on a display which is not turned on, and fails. There is detection logic in the startup code which tries to avoid this problem, but there may be edge cases still. If you see the console message: "WARNING: Window position out of bounds, falling back to primary display" something like this may be happening and the code is trying to recover by forcing the window back to your primary monitor.

One other possibility - I notice you have multiple graphics adaptors. Which one is being used for the game? Your 1050 has only 2GB of graphics memory which may be insufficient for supporting both your desktop and the game (which takes 1-2GB of graphics memory on its own, depending on window resolution). For DX12, you can force the game to use your 2080 (4 GB) by setting r_graphicsAdapter 2080in your autoexec.cfg file.

well for the graphics adapter the only display connected is currently connected to the rtx card. I do recieve the "WARNING: Window position out of bounds, falling back to primary display" message every time. I dont see Unable to initialize OpenGL during tests because I think the game fails on the device call before it can get to that line. also heres the relevent log file part using this set of autoexec settings and without my edit:

r_graphicsAdapter 2080
r_fullscreen -1
developer 1
logfile 2

logfile output:

r_graphicsAdapter is write protected and can only be set from the cmdline (or autoexec.cfg).
----- R_InitOpenGL -----
'RBDoom3BFG.exe' (Win32): Loaded 'C:\Windows\System32\mscms.dll'. 
'RBDoom3BFG.exe' (Win32): Loaded 'C:\Windows\System32\DXCore.dll'. 
'RBDoom3BFG.exe' (Win32): Loaded 'C:\Windows\System32\Windows.Internal.Graphics.Display.DisplayColorManagement.dll'. 
onecoreuap\windows\core\color\moderncolor\winrt\displaycolormanagement\lib\displaycolormanagement.cpp(34)\Windows.Internal.Graphics.Display.DisplayColorManagement.dll!00007FFE9C03C079: (caller: 00007FFEC1B93013) ReturnHr(1) tid(c08c) 80070057 The parameter is incorrect.
mscms.dll!00007FFEC1B9301E: LogHr(1) tid(c08c) 80070057 The parameter is incorrect.
onecoreuap\windows\core\color\mscms\internalgamma.cxx(302)\mscms.dll!00007FFEC1BBC0A4: (caller: 00007FFEC1BBB33B) ReturnHr(1) tid(c08c) 80070057 The parameter is incorrect.
    Msg:[winrt::hresult_error: The parameter is incorrect.] 
...getting default gamma ramp: failed
...registered window class
Exception thrown at 0x00007FFEFB37567C (KernelBase.dll) in RBDoom3BFG.exe: WinRT originate error - 0x80070057 : 'The parameter is incorrect.'.
Exception thrown at 0x00007FFEFB37567C in RBDoom3BFG.exe: Microsoft C++ exception: winrt::hresult_invalid_argument at memory location 0x00000039D18FDA40.
Exception thrown at 0x00007FFEFB37567C in RBDoom3BFG.exe: Microsoft C++ exception: [rethrow] at memory location 0x0000000000000000.
'RBDoom3BFG.exe' (Win32): Loaded 'C:\Windows\System32\bcrypt.dll'. 
WARNING: Window position out of bounds, falling back to primary display
r_fullscreen reset from 1 to 1 because mode list failed.
Going to safe mode because mode list failed.

------- Input Initialization -------
Initializing DirectInput...
'RBDoom3BFG.exe' (Win32): Loaded 'C:\Windows\System32\hid.dll'. 
'RBDoom3BFG.exe' (Win32): Loaded 'C:\Windows\System32\setupapi.dll'. 
'RBDoom3BFG.exe' (Win32): Loaded 'C:\Windows\System32\wintrust.dll'. 
'RBDoom3BFG.exe' (Win32): Loaded 'C:\Windows\System32\crypt32.dll'. 
'RBDoom3BFG.exe' (Win32): Loaded 'C:\Windows\System32\msasn1.dll'. 
mouse: Couldn't set DI coop level
------------------------------------
----- Initializing Render Shaders -----
Exception thrown: read access violation.
**device** was nullptr.
RobertBeckebans commented 4 months ago

Some users reported that renaming the home RBDOOM-3-BFG folder helps them if they ran older versions of RBDoom before.

Try to change C:\Users\yourname\Saved Games\id Software\RBDOOM 3 BFG but don't delete it so we can hunt that bug.

SRSaunders commented 4 months ago

Yes, we want to find that bug for sure. Your log output seems to indicate a problem with window position and monitors/display adaptors. The game is trying to start on what it thinks is the primary display on the first non-integrated graphics adaptor, which is likely your disconnected, no-monitor 1050. The line in the log that says "_rgraphicsAdapter is write protected and can only be set from the cmdline (or autoexec.cfg)." is important and means the option is not successfully set.

Does your autoexec.cfg look exactly like (sorry I meant 0 and not -1 for r_fullscreen):

set r_graphicsAdapter 2080
set r_fullscreen 0
...

Your log output should look like:

execing default.cfg
execing D3BFGConfig.cfg
execing autoexec.cfg
----- R_InitOpenGL -----
...
jfmherokiller commented 4 months ago

Yes, we want to find that bug for sure. Your log output seems to indicate a problem with window position and monitors/display adaptors. The game is trying to start on what it thinks is the primary display on the first non-integrated graphics adaptor, which is likely your disconnected, no-monitor 1050. The line in the log that says "_rgraphicsAdapter is write protected and can only be set from the cmdline (or autoexec.cfg)." is important and means the option is not successfully set.

Does your autoexec.cfg look exactly like (sorry I meant 0 and not -1 for r_fullscreen):

set r_graphicsAdapter 2080
set r_fullscreen 0
...

Your log output should look like:

execing default.cfg
execing D3BFGConfig.cfg
execing autoexec.cfg
----- R_InitOpenGL -----
...

tested adding set the options and now my autoexec.cfg file is this

set r_graphicsAdapter 2080
set r_fullscreen 0
developer 1
logfile 2

code still runs WARNING: Window position out of bounds, falling back to primary display

and the only thing in the RBDOOM save folder is the qconsole.log file.

new trimmed log file

couldn't exec D3BFGConfig.cfg
execing autoexec.cfg
----- R_InitOpenGL -----
...getting default gamma ramp: failed
...registered window class
WARNING: Window position out of bounds, falling back to primary display
r_fullscreen reset from 1 to 1 because mode list failed.
Going to safe mode because mode list failed.

------- Input Initialization -------
Initializing DirectInput...
mouse: Couldn't set DI coop level
------------------------------------
----- Initializing Render Shaders -----
Exception thrown: read access violation.
**device** was nullptr.

The program '[28616] RBDoom3BFG.exe' has exited with code 0 (0x0).
SRSaunders commented 4 months ago

Just to rule things out can you either plug a second monitor into your 1050 or pull it from your system and try again?

jfmherokiller commented 4 months ago

Just to rule things out can you either plug a second monitor into your 1050 or pull it from your system and try again?

I will try plugging in a second monitor (tbh the 1050s whole job was to simply run firefox so i could consult a guide while playing games or such).

Same error with 2nd montor installed.

SRSaunders commented 4 months ago

Thanks for trying that. Darn - this is a tricky one. I have one more request for now:

Please set the following in win_glimp.cpp, recompile and run:

line 220: bool verbose = true; line 442: bool verbose = true;

And report back with the log info.


Happy New Year! If you want to step through in the VS debugger and think it's failing on:

DeviceManager_DX12.cpp line 426: hr = pDxgiFactory->CreateSwapChainForHwnd( m_GraphicsQueue, ( HWND )windowHandle, &m_SwapChainDesc, &m_FullScreenDesc, nullptr, &pSwapChain1 );

Put a breakpoint on line 427: HR_RETURN( hr ); and look at m_SwapChainDesc, m_FullScreenDesc, and hr. I am interested in the hr return code value. And the input values should look similar to:

swapchaindesc

jfmherokiller commented 4 months ago

first the verbose code never seems to be run because this returns false

    DISPLAY_DEVICE  monitor;
    monitor.cb = sizeof( monitor );
    if( !EnumDisplayDevices(
                deviceName.c_str(),
                0,
                &monitor,
                0 /* dwFlags */ ) )
    {
        return false;
    }

and the only way it seems to reach 427 is if i add something like

if (deviceManager->GetDevice() == nullptr) deviceManager->CreateDeviceAndSwapChain();

but if i do add it the values are

hr = 0x887a0001z

image

this is using the autoexec contents of

set r_graphicsAdapter 2080
set r_fullscreen 0
developer 1
logfile 2
SRSaunders commented 4 months ago

Interesting, this info is saying you don't have any monitors attached to your display card and you are trying to create a swap chain of 0 x 0 dimensions, which will fail. The next step is to find out why.

Put a breakpoint at line 241 inside GetDisplayCoordinates() in win_glimp.cpp.

I am interested in the values of the following variables:

  1. deviceNum (passed in) and deviceName (defined by line 222)
  2. device.deviceName (defined in line 228, but set via line 233)
  3. device.DeviceString (defined in line 228, but set via line 233)

Alternatively, you can paste the following code into GetDisplayCoordinates(), replacing the existing code up to the point of if( verbose ). The log should then give us a lot more information about what is going on...

static bool GetDisplayCoordinates( const int deviceNum, int& x, int& y, int& width, int& height, int& displayHz )
{
    bool verbose = true;

    idStr deviceName = GetDeviceName( deviceNum );
    if( deviceName.Length() == 0 )
    {
        common->Printf( "^3GetDisplayCoordinates() - GetDeviceName() for display device %d failed^0\n", deviceNum );
        return false;
    }

    DISPLAY_DEVICE  device = {};
    device.cb = sizeof( device );
    if( !EnumDisplayDevices(
                0,          // lpDevice
                deviceNum,
                &device,
                0 /* dwFlags */ ) )
    {
        common->Printf( "^3GetDisplayCoordinates() - EnumDisplayDevices() for %s failed^0\n", deviceName.c_str() );
        return false;
    }

    DISPLAY_DEVICE  monitor;
    monitor.cb = sizeof( monitor );
    if( !EnumDisplayDevices(
                deviceName.c_str(),
                0,
                &monitor,
                0 /* dwFlags */ ) )
    {
        common->Printf( "^3GetDisplayCoordinates() - EnumDisplayDevices() for monitor on %s failed^0\n", device.DeviceString );
        return false;
    }

    DEVMODE devmode;
    devmode.dmSize = sizeof( devmode );
    if( !EnumDisplaySettings( deviceName.c_str(), ENUM_CURRENT_SETTINGS, &devmode ) )
    {
        common->Printf( "^3GetDisplayCoordinates() - EnumDisplaySettings() for %s on %s failed^0\n", monitor.DeviceString, device.DeviceString );
        return false;
    }

    if( verbose )
    {
    ...
SRSaunders commented 3 months ago

After looking deeper into this, I think I have found the problem: On Windows the numbering of desktop-connected displays returned by EnumDisplayDevices() can be non-contiguous across display adaptors. This was a big surprise (at least to me) and not the same as SDL which maintains contiguous numbering for active displays attached to the desktop.

I had to reconfigure my PC with multiple adaptors and monitors to see it - it is not evident if you have a single adaptor with multiple monitors attached. For instance, if you have a discrete card the display numbers correspond to the number of outputs, and if you combine this with an internal (or other external adaptor), there can be gaps in display numbering that correspond to the unused outputs of the various cards in your system. Fortunately, most of the code in RBDoom3BFG is tolerant of this, but there were some paths in the startup code that assumed the first display was always 0 (or fullscreen = 1), which may not be correct in these multi-adaptor, multi-monitor setups. In addition, there was another code path in the monitor/resolution selection menu that assumed contiguous display numbering, which again was not correct. It also likely explains why querying for monitors sometimes returned false in your example above, and hopefully explains your startup failures (even after falling back to the primary display and safe mode).

I have a test branch (that is up to date with @RobertBeckebans current master) with the required changes added. See: https://github.com/SRSaunders/RBDOOM-3-BFG/tree/init-shutdown-fixes

I would appreciate it if @jfmherokiller would test this branch to see if it addresses your problem. If it does, I will create a pull request to submit into master. Please test windowed and fullscreen modes at startup as well as in-game to make sure things are working properly.

Note the one weird side-effect of this fix is that on Windows you may see odd numberings for the Monitors listed in the resolution selection menu when multiple display adaptors are being used. For instance, in my setup I can see Monitors numbered 1 (or 2 if a cable is hot-unplugged) and 7 corresponding to my discrete card and my internal iGPU respectively.

Here are some screenshots of my setup on Windows 10 showing Monitor 2 (6600XT) and Monitor 7 (Intel iGPU): rbdoom-3-bfg-20240107-182300-001

rbdoom-3-bfg-20240107-182316-002

RobertBeckebans commented 3 months ago

Thank you @SRSaunders for looking into this. If @jfmherokiller could test this and it fixes the bug then this could be merged into master.

SRSaunders commented 3 months ago

@RobertBeckebans while we wait for @jfmherokiller to test this, I have a question about initial window placement behaviour. At startup in non-fullscreen mode (r_fullscreen = 0), the current behaviour is to centre the window on the primary display, independent of which display was being used when the game last exited. The rationale for this was to ensure you always have a valid display to start on. However, when making the changes in this branch I considered changing this to centre the window on the last display used (from previous exit). The argument being if you prefer a certain display for the game, would it be preferable to startup on that same screen again. And if this screen is no longer available (unplugged or off), I could then fall back to primary as before. Would this be a useful change for non-fullscreen mode? If so I could add it to this branch. Note this would not change behaviour when starting up in fullscreen mode on your preferred display - that works today and would not change.