请参阅下面的编辑更新。 原始问题已被修改!
我有一个使用DX11设备的工作窗口。 当我尝试使用Alt + Enter全屏时,出现问题。 如果窗口没有聚焦,我得到一个debugging输出,说:
'MyGame.exe': Loaded 'C:\Windows\SysWOW64\D3D10SDKLayers.DLL', Cannot find or open the PDB file
然后警告
DXGI Warning: IDXGISwapChain::Present: Fullscreen presentation inefficiencies incurred due to application not using IDXGISwapChain::ResizeBuffers appropriately, specifying a DXGI_MODE_DESC not available in IDXGIOutput::GetDisplayModeList, or not using DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH
我相当确定一个DX11游戏不应该加载D3D10SDKLayers.dll,特别是在执行中。 从MSDN文档,我收集到这个DLL是在设备创build时加载的: if a device is created with the appropriate layer flag, this DLL is loaded automatically
。 所以我查了一下,看看我的设备创build方法在执行过程中是否被调用,而不是。 在我的游戏中,只有2个位置存在设备创build点,两个点都没有被击中。 编辑:在检查MSDN后,似乎这个DLL只是一个debuggingDLL,可能只是加载打印出来的警告本身,没有其他的目的。
明确的复制情况:
1)Alt + Enter 6次(3个全屏转换循环,两种方式,开始窗口),7日dll被加载,并popup警告。 无论窗口对焦如何
方法调用层次摘要(全屏):
1)ToggleFullscreen() – 我的方法,只有通过Alt + Enter调用的方法
2)ResizeTargetAndBuffers() – 我的方法,下面的子方法
3)DXGISwapChain-> ResizeTarget(frontBufferDesc)将前台缓冲区大小调整为指定的res
4)DXGISwapChain-> GetFullscreenState()来确定全屏状态
5)DXGISwapChain-> SetFullscreenState(TRUE,NULL)去全屏
6)ResizeDXGIBuffers(width,height,TRUE)我的方法,调整后台缓冲区大小,子方法如下
7)DXGISwapChain-> ResizeBuffers(count,width,height,format,flags)调整后台缓冲区
8)DXGISwapChain-> ResizeTarget(frontBufferDesc)可以防止刷新率问题。 根据MSDN最佳实践,RefreshRate成员归零。
9)DXGISwapChain-> GetFullscreenState()来确定全屏状态
方法调用层次摘要(去窗口):
1)ToggleFullscreen() – 我的方法,只有通过Alt + Enter调用的方法
2)ResizeTargetAndBuffers() – 我的方法,下面的子方法
3)DXGISwapChain-> ResizeTarget(backBufferDesc)将前台缓冲区的大小调整为指定的res
4)DXGISwapChain-> GetFullscreenState()来确定全屏状态
5)DXGISwapChain-> SetFullscreenState(FALSE,NULL)去全屏
6)DXGISwapChain-> ResizeTarget(backBufferDesc)将前台缓冲区的大小调整为窗口的res(帮助解决了一些问题)
7)ResizeDXGIBuffers(width,height,FALSE)我的方法,调整后台缓冲区大小,子方法如下
8)DXGISwapChain-> ResizeBuffers(计数,宽度,高度,格式,标志)调整后台缓冲区的大小
9)DXGISwapChain-> GetFullscreenState()来确定全屏状态
这种影响相当严重。 捕获Alt + Enter的低级键盘钩子不再被调用,所以windows能够执行自动的Alt + Enter处理,它完全绕过了我的ToggleFullscreen方法,并将窗口设置为桌面分辨率。 这会导致缓冲区大小错误(因为我没有设置它们,窗口也是这样),导致无效的警告,并且弄乱了我的程序中的variables,这些variables不再具有缓冲区大小的正确知识,窗口是否全屏或不。
任何想法可能是什么原因造成的?
PS如果您需要代码示例,请详细说明您想要查看的内容,如果可能的话,我会尝试将其提取出来。 我不能把整个代码清单。
编辑:设备创build代码如下。
hr = D3D11CreateDevice( pAdapter, driverType, NULL, rDeviceSettings.m_CreateFlags, &rDeviceSettings.m_eD3DDeviceFeatureLevel, 1, D3D11_SDK_VERSION, &pGraphicsDevice, &eFeatureLevel, &pDeviceContextI ); if ( FAILED( hr ) ) { pAdapter = NULL; // Remote desktop does not allow you to enumerate the adapter. In this case, we let D3D11 do the enumeration. if ( driverType == D3D_DRIVER_TYPE_UNKNOWN ) { hr = D3D11CreateDevice( pAdapter, driverType, NULL, rDeviceSettings.m_CreateFlags, &rDeviceSettings.m_eD3DDeviceFeatureLevel, 1, D3D11_SDK_VERSION, &pGraphicsDevice, &eFeatureLevel, &pDeviceContextI ); }
第一次通话成功的时间是99%,即当你不使用远程桌面时,所以我只关注它。 我给它的适配器,driverType为D3D_DRIVER_TYPE_HARDWARE,m_CreateFlags为D3D11_CREATE_DEVICE_DEBUG,m_eFeatureLevel为D3D_FEATURE_LEVEL_11_0。 相当标准的通话,它总是成功的。
编辑更新1:经过一些广泛的debugging后,我发现,当DLL加载和低效率的警告popup,一些非常有趣的情况出现。 如下所列:
1)VS2010debugging器不再触发键挂钩中的断点。
2)打印输出不再在钥匙钩中工作。
3)如果之前可以resize的话,窗口可能会变得不可调整
4)窗口可能会变成不可移动的。
5)三重线程退出。
编辑更新2:第一次编辑更新可能有不正确的假设; 如果我find了,我会删除它。 事实certificate,我的低级别的关键钩子不再被调用(我认为,因为没有断点或打印语句在里面工作),所以如果我的程序中的东西注意到它意外注册那么会导致所有上述问题。 明天testing这个…
编辑更新3:我不知道发生了什么事了。 我在家用电脑和工作电脑上testing了同样的清洁工程,得到了不同的结果。 在家里,我可以无限期地Alt + Enter,而不会出现任何问题,但在工作Alt + Enter第七次导致不再调用密钥钩子和缓冲区问题发生。
编辑更新4:更多的testing(在工作)。 在第三次转换到窗口模式之后,键钩肯定会被移除。 它不再在关键的钩子方法内部打印,而且不pipe触发什么键都不触发断点。 我想我会打开一个单独的问题,因为我上面描述的所有其他问题只是不调用ToggleFullscreen()的这个关键的钩子的后果。 作为参考,我在下面提供了关键的钩子代码。
LRESULT _stdcall MyClass::WindowsKeyHook( s32 nCode, WPARAM wParam, LPARAM lParam ) { printf("Key hook called, nCode: %d. ", nCode); if( nCode < 0 || nCode != HC_ACTION ) { // do not process message return CallNextHookEx( MyClassVar.GetWindowsKeyHook(), nCode, wParam, lParam ); } printf(" Key hook status ok.\n"); BOOL bEatKeystroke = FALSE; KBDLLHOOKSTRUCT* p = ( KBDLLHOOKSTRUCT* )lParam; switch( wParam ) { //NOTE: Alt seems to be a system key when it is PRESSED, but a regular key when it is released... case WM_SYSKEYDOWN: if(p->vkCode == VK_MENU || p->vkCode == VK_LMENU || p->vkCode == VK_RMENU) { MyClassVar.SetAltPressed(TRUE); } if(MyClassVar.IsAltPressed() && p->vkCode == VK_RETURN) { bEatKeystroke = TRUE; MyClassVar.SetAltEnterUsed(TRUE); printf("Alt+Enter used.\n"); } break; case WM_SYSKEYUP: //NOTE: releasing alt+enter causes a SYSKEYUP message with code 0x13: PAUSE key... break; case WM_KEYDOWN: break; case WM_KEYUP: { if(p->vkCode == VK_MENU || p->vkCode == VK_LMENU || p->vkCode == VK_RMENU) { MyClassVar.SetAltPressed(FALSE); } bEatKeystroke = ( !MyClassVar.IsShortcutKeysAllowed() && ( p->vkCode == VK_LWIN || p->vkCode == VK_RWIN ) ); break; } } if( bEatKeystroke ) { return 1; } else { return CallNextHookEx( MyClassVar.GetWindowsKeyHook(), nCode, wParam, lParam ); } }
printf语句显示在第六个Alt + Enter之后,键钩被调用。 这是窗口模式的第三次转换。 正如我之前所想的那样,我没有必要第四次全屏显示这个问题。 所有由MyClassVar调用的方法都是内联的,以使得关键钩子尽可能快,因为我知道在windows关键钩子上有一个超时。 Alt + Enter的实际处理由MyClass中的线程处理。
另外,有人可以让这不是一个社区维基? 我认为这个问题太具体,不能用作维基。 成为一个唯一的原因是我已经定期更新与编辑。
我彻底解决了这个问题。 处理Alt + Enter的正确方法是创建交换链,然后调用IDXGIFactory1::MakeWindowAssosciation( m_hWnd, DXGI_MWA_NO_ALT_ENTER)
。 然后,您可以使用WM_SYSKEYDOWN
和WM_KEYUP
从Windows消息过程中处理Alt + Enter。 我希望这可以帮助别人! 我有一个时间让这个工作,所以如果你很难得到它在你自己的应用程序的工作,给我一个消息,我会尽力帮助你!