mohamed.irshad.k Posted February 14, 2012 Share Posted February 14, 2012 We are using Direct3D9 in our Unigine::App. While in full screen, if the app loses focus, it cannot recover. I tried the IDirect3DDevice9::Reset() but it fails saying that all the resources need to be released before reseting the device. What is the best way to handle this situation? Link to comment
manguste Posted February 16, 2012 Share Posted February 16, 2012 There's a bit of magic when handling lost Direct3D 9 devices. When the device is lost, a windowed mode is set instead, which does the trick. Check source\engine\render\direct3d9\framework\D3D9AppWindow.cpp: if(app->d3d->CreateDevice(adapter,type,window,flags,&app->d3dpp,&app->device) != S_OK) { SAFE_RELEASE(app->device); app->d3dpp.Windowed = TRUE; Log::warning("Set non-exclusive video mode\n"); if(D3D9Ext::error(app->d3d->CreateDevice(adapter,type,window,flags,&app->d3dpp,&app->device))) { Log::error("D3D9AppWindow::create_context(): CreateDevice(): failed\n"); SAFE_RELEASE(app->device); SAFE_RELEASE(app->d3d); return 0; } } Link to comment
mohamed.irshad.k Posted February 21, 2012 Author Share Posted February 21, 2012 I tried as you suggested but it didn't succeed. Please note that we don't have the source code of Unigine. Can you please elaborate a little more on what should be done. Below is what I am doing when device is lost: void UnigineApp::doRender() { HRESULT hr = m_pD3DDevice9->TestCooperativeLevel(); if( hr == D3D_OK ) { render(); } else if( hr == D3DERR_DEVICENOTRESET ) { m_paramsD3DPresent.Windowed = TRUE; hr = m_pD3DDevice9->Reset( &m_paramsD3DPresent ); } else { sleep(500); m_bNeedDestory = true; } } Link to comment
mohamed.irshad.k Posted May 11, 2012 Author Share Posted May 11, 2012 We still haven't resolved the problem. We tried modifying the code as per D3D9AppWindow.cpp which you had sent by email but still the error exists. The IDirect3DDevice9::Reset() returns D3DERR_INVALIDCALL instead of D3D_OK and there after the program crashes. We tried by using the DirectX debug dlls to see exactly whats is the error message and it is saying that all the resources must be released before calling Reset(). Below is the relevant part of our Unigine::App and the error happnes inside CRenderWindow::doUpdate_Private() on calling Reset(). // CRenderWindow inherits class App // CRenderWindow : public Unigine::App bool CRenderWindow::InitDirect3D9() { int nFlags = m_nFlagsUnigine; if(m_pD3D9 != NULL) { App::shutdownD3D9(); SAFE_RELEASE( m_pD3DDevice9 ); SAFE_RELEASE( m_pD3D9 ); m_bNeedDestory = true; } if(m_pD3D9 == NULL) { m_pD3D9 = Direct3DCreate9(D3D_SDK_VERSION); if( !m_pD3D9 ) { Trace( L"Error\n"); return false; } } // present parameters memset(&m_paramsD3DPresent,0,sizeof(m_paramsD3DPresent)); m_paramsD3DPresent.BackBufferWidth = m_nWidth; m_paramsD3DPresent.BackBufferHeight = m_nHeight; m_paramsD3DPresent.BackBufferFormat = D3DFMT_A8R8G8B8; m_paramsD3DPresent.BackBufferCount = (nFlags & VSYNC) ? 2 : 1; if( nFlags & RENDERSCREEN ) { if(nFlags & MULTISAMPLE_2) m_paramsD3DPresent.MultiSampleType = D3DMULTISAMPLE_2_SAMPLES; if(nFlags & MULTISAMPLE_4) m_paramsD3DPresent.MultiSampleType = D3DMULTISAMPLE_4_SAMPLES; if(nFlags & MULTISAMPLE_8) m_paramsD3DPresent.MultiSampleType = D3DMULTISAMPLE_8_SAMPLES; } else { m_paramsD3DPresent.MultiSampleType = D3DMULTISAMPLE_NONE; } // device caps D3DCAPS9 caps; m_pD3D9->GetDeviceCaps(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,&caps); if( m_pD3D9->CheckDeviceMultiSampleType( caps.AdapterOrdinal, caps.DeviceType, D3DFMT_A8R8G8B8, m_bWindowed, m_paramsD3DPresent.MultiSampleType, NULL) != S_OK ) { Trace( L"RenderWindow: required multisample is not supported\n"); SAFE_RELEASE(m_pD3D9); return false; } m_paramsD3DPresent.SwapEffect = D3DSWAPEFFECT_DISCARD; m_paramsD3DPresent.hDeviceWindow = m_hWnd; m_paramsD3DPresent.Windowed = m_bWindowed; m_paramsD3DPresent.EnableAutoDepthStencil = TRUE; m_paramsD3DPresent.AutoDepthStencilFormat = D3DFMT_D24S8; m_paramsD3DPresent.PresentationInterval = (nFlags & VSYNC) ? D3DPRESENT_INTERVAL_ONE : D3DPRESENT_INTERVAL_IMMEDIATE; // create m_pD3DDevice9 UINT iAdapter = D3DADAPTER_DEFAULT; D3DDEVTYPE deviceType = D3DDEVTYPE_HAL; nFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES; if( caps.VertexProcessingCaps ) nFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING; else nFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING; HRESULT hr = m_pD3D9->CreateDevice( iAdapter, deviceType, m_hWnd, nFlags, &m_paramsD3DPresent, &m_pD3DDevice9 ); if(hr != D3D_OK) { SAFE_RELEASE(m_pD3DDevice9); m_paramsD3DPresent.Windowed = TRUE; Trace( L"RenderWindow: Set non-exclusive video mode\n" ); hr = m_pD3D9->CreateDevice( iAdapter, deviceType, m_hWnd, nFlags, &m_paramsD3DPresent, &m_pD3DDevice9 ); if(hr != D3D_OK) { Trace( L"RenderWindow: CreateDevice(): failed\n"); SAFE_RELEASE( m_pD3DDevice9 ); SAFE_RELEASE(m_pD3D9 ); return false; } } // clear buffers m_pD3DDevice9->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, D3DCOLOR_RGBA(0,0,0,0), 1.0f, 0 ); // initialize Direct3D9 int nSuccess = initD3D9(m_pD3D9,m_pD3DDevice9); return nSuccess != 0; } int CRenderWindow::setVideoMode(int nWidth,int nHeight,int nFlags/* = 0*/,int nRefresh/* = 0*/) { // window is not resizeable. So not using the given size m_nFlagsUnigine = nFlags; return this->InitDirect3D9(); } // Called Every frame void CRenderWindow::Update() { this->doUpdate_Private(); this->doRender_Private(); this->doSwap_Private(); } void CRenderWindow::doUpdate() { } void CRenderWindow::doRender() { } void CRenderWindow::doSwap() { } void CRenderWindow::doUpdate_Private() { // release dynamic buttons if(m_nMouseButtonMask & BUTTON_UP) { m_nMouseButtonMask &= ~BUTTON_UP; buttonRelease(BUTTON_UP); } if(m_nMouseButtonMask & BUTTON_DOWN) { m_nMouseButtonMask &= ~BUTTON_DOWN; buttonRelease(BUTTON_DOWN); } if(m_nMouseButtonMask & BUTTON_DCLICK) { m_nMouseButtonMask &= ~BUTTON_DCLICK; buttonRelease(BUTTON_DCLICK); } if( !m_pD3DDevice9 ) return; HRESULT hr = m_pD3DDevice9->TestCooperativeLevel(); if( hr == D3DERR_DEVICELOST ) { ShowWindow( m_hWnd, SW_MINIMIZE ); this->stopFps(); PLib::Sleep( 1000 ); m_bNeedDestory = true; this->startFps(); return; } else if( hr == D3DERR_DEVICENOTRESET ) { hr = m_pD3DDevice9->Reset( &m_paramsD3DPresent ); // Assert fails. Value of hr is D3DERR_INVALIDCALL assert_debug( hr == D3D_OK ); this->InitDirect3D9(); return; } else if( hr == D3DERR_DRIVERINTERNALERROR ) { Trace( L"internal driver error\n" ); return; } else if(hr != D3D_OK ) { Trace( CString( 50, L"can't test cooperative level 0x%x\n", hr ) ); return; } update(); } void CRenderWindow::doRender_Private() { if( m_pD3DDevice9 == NULL) return; render(); } void CRenderWindow::doSwap_Private() { if( m_pD3DDevice9 == NULL ) return; this->swap(); HRESULT hr = m_pD3DDevice9->Present( NULL, NULL, NULL, NULL ); if( hr == D3DERR_DRIVERINTERNALERROR) { Trace( L"internal driver error\n" ); } else if( hr != D3DERR_DEVICELOST ) { Trace( CString( 50, L"can't present device 0x%x\n", hr ) ); } } Link to comment
unclebob Posted May 22, 2012 Share Posted May 22, 2012 Hello Mohamed, Sorry for late reply. Have you tried to always set non-exclusive fullscreen mode? Link to comment
mohamed.irshad.k Posted May 22, 2012 Author Share Posted May 22, 2012 I have tried the non-exclusive fullscreen mode and works well. The exclusive fullscreen mode is the problem. Link to comment
unclebob Posted May 22, 2012 Share Posted May 22, 2012 The problem is engine will not reload all data when device is lost, instead of that it tries to set non-exclusive fullscreen mode (hack detected). So, there is no solution for exclusive fullscreen mode right now, sorry. But non-exclusive fullscreen mode should suit your needs, isn't it? Link to comment
mohamed.irshad.k Posted May 23, 2012 Author Share Posted May 23, 2012 The problem with non-exclusive fullscreen mode is that the game's resolution has to match the desktop resolution. Mostly this is not acceptable for machines with low end config. If the desktop resolution is high, e.g.: 1920x1080, then on a low-end machine the FPS will be dramatically low making it almost unplayable. So we must be able support non-desktop resolutions in fullscreen and I guess our only option is to go with the exclusive fullscreen mode. Link to comment
unclebob Posted May 23, 2012 Share Posted May 23, 2012 You can set proper video mode first and then setup non-exclusive fullscreen mode. Please look at source\plugins\common\AppWindow.cpp file. Take your attention to AppWindow::setVideoMode method. It does the work. Link to comment
mohamed.irshad.k Posted May 25, 2012 Author Share Posted May 25, 2012 Thanks unclebob for the suggestion. The solution, as I understand it, is to change the desktop resolution to the game's resolution and initialize Direct3D9 with same resolution. I am skeptical about what will happen when game crashes and it didn't get a chance to reset the desktop resolution back to the user's settings - the user will have to change the settings manually. This is an extra annoyance in addition to the game's crash. It'd be nice if we got a robust solution to this from Unigine. Link to comment
manguste Posted May 30, 2012 Share Posted May 30, 2012 Even if the application crashes, the system restores screen resolution (both in Win7 and XP) so the user does not have to do it manually. Link to comment
mohamed.irshad.k Posted June 20, 2012 Author Share Posted June 20, 2012 Yes, on Win7 the resolution is restored on app crash. So far this solution is working without any crash on fullscreen switching. Thanks unclebob ;) Link to comment
Recommended Posts