为什么我的DX11游戏会加载D3D10SDKLayers.dll?

4

请查看下面的编辑更新。原始问题已被修改!

我有一个使用DX11设备的工作窗口。当我尝试使用Alt+Enter全屏时,遇到了问题。如果窗口没有焦点,我会得到一个调试输出,上面写着:

'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是在设备创建时加载的:如果使用适当的层标志创建设备,则自动加载此DLL。因此,我检查了一下我的设备创建方法是否在执行过程中被调用,但它们没有被调用。我的游戏中只有两个位置存在设备创建,而且都没有被访问。
编辑:经过检查MSDN,似乎这个dll只是一个调试dll,并且可能只是为了打印出警告本身而加载,没有其他目的。

明确的复现情况:

1)使用Alt+Enter 6次(3个全屏过渡周期,双向,从窗口开始),在第7次时加载dll并弹出警告。无论是否聚焦于窗口,都会发生这种情况。

方法调用层次结构摘要(进入全屏模式):

1)ToggleFullscreen() - 我的方法,仅由Alt+Enter调用
2)ResizeTargetAndBuffers() - 我的方法,下面是子方法
3)DXGISwapChain->ResizeTarget(frontBufferDesc) 将前缓冲区调整为指定的分辨率
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)将前缓冲区的大小调整为指定的分辨率
4) DXGISwapChain->GetFullscreenState()以确定全屏状态
5) DXGISwapChain->SetFullscreenState(FALSE, NULL)进入全屏模式
6) DXGISwapChain->ResizeTarget(backBufferDesc)将前缓冲区的大小调整为窗口的分辨率(有助于解决一些分辨率问题)
7) ResizeDXGIBuffers(width, height, FALSE)这是我的方法,调整后缓冲区的大小,下面有子方法
8) DXGISwapChain->ResizeBuffers(count, width, height, format, flags)调整后缓冲区的大小
9) DXGISwapChain->GetFullscreenState()以确定全屏状态

这将会产生相当严重的影响。我的低级键盘钩子不再被调用,所以Windows能够进行自动的Alt+Enter处理,完全绕过了我的ToggleFullscreen方法,并将窗口设置为桌面分辨率。这导致缓冲区的大小不正确(因为我没有设置它们,Windows已经设置了),导致效率警告,并且干扰了我的程序中的变量,这些变量不再具有正确的缓冲区大小和窗口是否全屏等信息。

你有什么想法是什么导致了这个问题吗?

P.S. 如果您需要代码示例,请具体说明您想要看到什么,如果可能的话,我会尝试将其放在上面。我无法发布整个代码列表。

编辑:设备创建代码如下。


         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%,即当您未使用远程桌面时,因此我将仅关注它。我将其赋予适配器,驱动程序类型为D3D_DRIVER_TYPE_HARDWARE,m_CreateFlags为D3D11_CREATE_DEVICE_DEBUG,m_eFeatureLevel为D3D_FEATURE_LEVEL_11_0。相当标准的调用,它总是成功的。
编辑更新1:经过大量调试,我发现当加载dll并弹出效率警告时,会出现一些非常有趣的情况。它们如下所列:
1)VS2010调试器不再触发关键钩子中的断点。 2)关键钩子中的打印输出不再起作用。 3)如果之前可调整大小,则窗口可能变得不可重新调整大小。 4)窗口可能变得无法移动。 5)三个线程退出。
编辑更新2:第一个编辑更新可能存在错误的假设;如果我发现它确实存在,则会删除它。事实证明,我的低级关键钩子不再被调用(我认为,因为在其中没有断点或打印语句工作),因此,如果我的程序中的某些内容意外取消注册它,则会导致上述所有问题。明天测试这个......
编辑更新3:我不确定现在发生了什么。我在家庭电脑和工作电脑上测试了同样的清洁项目,并获得了不同的结果。在家里,我可以无限制地使用Alt+Enter而没有任何问题发生,但是在工作中,第7次Alt+Enter导致关键钩子不再被调用并且缓冲区问题发生。
编辑更新4:更多测试(在工作中)。关键钩子绝对会在第3次过渡到窗口模式后被删除。它不再在关键钩子方法内部打印,并且无论按下哪个键都不触发断点。我认为我将单独提出一个问题,因为上述所有问题都只是这个关键钩子不调用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中的一个线程处理。

此外,有人能使这不成为社区维基吗?我认为这个问题过于具体,不能作为维基使用。它变成维基的唯一原因是我经常进行编辑更新。


你提到设备创建不会在执行过程中发生,但是,标志位不能从初始设备创建中获取吗?此外,能否展示一下你的设备创建过程,这可能会有所帮助。 - josephthomas
@josephthomas 我已添加所请求的代码。我怀疑标志不是来自初始设备创建,因为只有在切换到全屏时才会收到警告。这对我来说表明我的全屏切换代码存在错误,但我不知道是什么。 - Darkhydro
1个回答

1

我通过完全删除键钩解决了这个问题。处理Alt+Enter的正确方法是创建交换链,然后调用IDXGIFactory1::MakeWindowAssosciation(m_hWnd, DXGI_MWA_NO_ALT_ENTER)。然后您可以使用WM_SYSKEYDOWNWM_KEYUP从您的Windows消息过程中使用自己的代码来处理Alt+Enter。希望这能帮助其他人!我曾经花费了很长时间才使其正常工作,所以如果您在自己的应用程序中遇到了困难,请给我发消息,我会尽力帮助您!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接