Recover full screen device, procedurally from other process.

Started by
3 comments, last by Balk 11 years, 1 month ago

I have a multi-monitor, multi-full screen dx9 device setup that need to work hand-in-hand with another process. This other process can make the dx9 app minimize so it can take the active foreground window... and when it's done, it signals the dx9 app (via local telnet) to recover itself and become active again.

My finished product needs to accomplish this procedurally, as in I cannot use any input devices to either alt-tab or click the dx9 app in taskbar with mouse. When I try to do it procedurally, the different recovery code I've tried has managed to create two different outcomes.

  • The dx9 app does maximize, and recovers... but when I click the screen, if any windows are behind the game it immediately loses focus, as if the dx9 app is only rendering overtop the other windows but not actually there.
  • Or, the game comes back up, but shows only a white screen and the device is reports 'D3DERR_DEVICELOST', and never makes it to 'D3DERR_DEVICENOTRESET'... but if you actually click the screen it receives the input properly and plays the game.

I'm almost certain I'm freeing all the dx resources that I need to be, and that it's got to be some sort of focus issue.

I'm also aware that AllowSetForegroundWindow(), needs to present in the other process to be able to give up focus, and it is being called.

The dx9 app is a fairly large engine, so posting the code is a concise matter will be difficult, below is the general idea of things:

All code is from dx9 app:


//
// A message comes in whether to minimize/maximize
if(m_bMinimize)
{
    LOG("minimize!");
    ShowWindow(deviceRef.GetWnd(), SW_MINIMIZE);//SW_HIDE);
}
else
{
    LOG("MAXIMIZE!");
    ShowWindow(deviceRef.GetWnd(), SW_SHOWNORMAL);
    SetForegroundWindow(deviceRef.GetWnd());
}

The below function CheckDevice() is called at the beginning of the render thread loop. It returns whether or not the device is okay.


// Returns true if it's okay to render
bool LtGRenderThread::CheckDevice()
{
    if(m_bLostDevice)
    {
        int j = 0;
	for(j = 0; j < m_iNumDevices; j++) //for(int j = m_iNumDevices-1; j >= 0; --j)
	{
	    HRESULT result = m_pDevices[j].m_pD3DDevice->TestCooperativeLevel();
	    if(FAILED(result))
	    {
	        if(D3DERR_DEVICENOTRESET == result)
		{
		    HRESULT result2 = m_pDevices[j].m_pD3DDevice->Reset(&m_pDevices[j].m_tPresentParams);

		    if(FAILED(result2))
		    {
			LOGF("Device %i: reset failed: %u", LOG_NORMAL, j, result2);			                                              }
		    else
		    {
			LOGF("Device %i: Reset successful...", LOG_NORMAL, j);
		    }
		}
                    break;
		
            }
	    else
	        LOGF("DEVICE %i has recovered!", LOG_TODO, j);
	}

	if(j == m_iNumDevices)
	{
	    LOG("Reloading all vRAM...");

	    for(j = 0; j < m_iNumDevices; j++)
	    {
	        m_pDevices[j].OnResetDevice();
	    }
	
	    // Tell Update thread that we need to reset the device
	    m_MsgManRef.MarkFlag(MSGMAN_ResetDevice);

	    m_bLostDevice = false;
        }
    }
    else
    {
	for(int j = 0; j < m_iNumDevices; j++)
	{
            HRESULT result = m_pDevices[j].m_pD3DDevice->TestCooperativeLevel();
	    if(FAILED(result) || m_pDevices[j].IsForceReset())
	    {
		LOG("A device has been lost! (Or forced to reset)");

		m_bLostDevice = true;
				
		// Clear out all DX resources
		for(int i = 0; i < m_iNumDevices; i++)
		    m_pDevices[i].OnLostDevice();

		m_MsgManRef.MarkFlag(MSGMAN_LostDevice);

	        break;
	    }
        }
    }
	
    return !m_bLostDevice;
}

I'm pretty sure no one is going to respond to this mess. But I'll just try to be hopeful that someone has some experience in doing something similar to this. Thanks for reading.

Can I play with madness?

Advertisement

Are you releasing all of your device resources, including textures, vertex buffers, essentially anything created by D3D? I'm only seeing the device currently, and it can't reset properly until all resources have been released.

Perception is when one imagination clashes with another

Are you releasing all of your device resources, including textures, vertex buffers, essentially anything created by D3D? I'm only seeing the device currently, and it can't reset properly until all resources have been released.

Yeah, the m_pDevices[j].OnLostDevice(); is handling all of that within. I am able to have it recover properly when I use the mouse and keyboard to select the minimized application. That's why I'm pretty certain it's some sort of focus issue.


void LtGDevice::OnLostDevice()
{
	m_pD3DSprite->OnLostDevice();

	SAFE_RELEASE(m_pBackBuffer);
	SAFE_RELEASE(m_swapChain);

	// Kill all the tasks... they will be repopulated upon DeviceReset
	for(unsigned int i = 0; i < m_vScheduledTasks.size(); i++)
	{
		SAFE_DELETE(m_vScheduledTasks[i]);
	}
	m_vScheduledTasks.clear();

	for(map<int, LPDIRECT3DTEXTURE9>::iterator iter = m_mapTextures.begin(); iter != m_mapTextures.end(); ++iter)
	{
		SAFE_RELEASE(iter->second);
	}

	for(map<FONT_HANDLE, LPD3DXFONT>::iterator iter = m_mapFonts.begin(); iter != m_mapFonts.end(); ++iter)
	{
		iter->second->OnLostDevice();
	}

	m_bForceReset = false;
}

Can I play with madness?

Hmm... this is a shot in the dark, but with your first case, is it possible you're using DirectInput and are not resetting it? I believe there was some shenanigans with the HWND when the device is lost, but honestly, I haven't had to deal with OnLost and OnReset in two years or so.

Perception is when one imagination clashes with another

I'm handling all the input through the traditional WndProc message callbacks. I have a feeling I might be incorrectly using AllowSetForegroundWindow in the process that is supposed to give up focus when its done to the dx9 app, and that is what's causing the weird "rending on top, but input falls through to the windows behind".

Thanks, for helping tho!

Can I play with madness?

This topic is closed to new replies.

Advertisement