为什么在 DX11 游戏期间加载 D3D10SDKLayers.dll?

发布于 2024-12-27 23:13:25 字数 6697 浏览 0 评论 0原文

请参阅下面的编辑更新。原问题已修改!

我有一个使用 DX11 设备的工作窗口。当我尝试使用 Alt+Enter 进入全屏时,我的问题出现了。如果窗口没有聚焦,我会得到一个调试输出:

'MyGame.exe': Loaded 'C:\Windows\SysWOW64\D3D10SDKLayers.DLL', Cannot find or open the PDB file

和然后警告

DXGI 警告:IDXGISwapChain::Present:由于应用程序不使用 IDXGISwapChain::ResizeBuffers 而导致全屏演示效率低下适当地,指定 IDXGIOutput::GetDisplayModeList 中不可用的 DXGI_MODE_DESC,或者不使用 DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH

我相当确定 DX11 游戏不应该加载 D3D10SDKLayers.dll,尤其是在执行过程中。从 MSDN 文档中,我了解到该 DLL 在创建设备时加载:如果使用适当的层标志创建设备,则自动加载该 DLL。因此,我检查了我的设备创建方法是否在执行过程中以某种方式被调用,但事实并非如此。我的游戏中只有 2 个位置存在设备创建,但两个位置都没有被击中。 编辑:检查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) 防止刷新率问题。 RefreshRate 成员根据 MSDN 最佳实践进行清零。
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() 来确定全屏状态

这样做的后果是相当严重的。我捕获 Alt+Enter 的低级键盘钩子不再被调用,因此 Windows 能够执行自动 Alt+Enter 处理,这完全绕过我的 ToggleFullscreen 方法并将窗口设置为桌面分辨率。这会导致缓冲区大小错误(因为我没有设置它们,而是 Windows 这样做了),导致效率低下的警告,并扰乱了我的程序中的变量,这些变量不再正确了解缓冲区大小以及窗口是否全屏或不。

关于可能导致此问题的任何想法?

PS 如果您需要代码示例,请具体说明您想查看的内容,如果可能的话,我会尽力将其提供。我无法列出整个代码清单。

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


         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:经过一些广泛的调试,我发现当加载dll并弹出低效警告时,会出现一些非常有趣的情况。下面列出了它们:

1) VS2010 调试器不再在关键钩子中触发断点。
2) 打印输出在钥匙钩中不再起作用。
3) 如果窗口之前调整过大小,则可能会变得不可调整大小
4) 窗口可能变得不可移动。
5) 三个线程退出。

编辑更新2:第一次编辑更新可能有不正确的假设;如果我发现它,我会删除它。事实证明,我的低级关键钩子不再被调用(我认为,因为其中没有断点或打印语句工作),所以如果我的程序中的某些内容意外地注销了它,那么这将导致上述所有问题。明天测试一下...

编辑更新 3:我不确定发生了什么。我在家用计算机和工作计算机上测试了相同的干净项目,并得到了不同的结果。在家里,我可以无限期地按 Alt+Enter,不会出现任何问题,但在工作中,第七次 Alt+Enter 会导致不再调用键挂钩并发生缓冲区问题。

编辑更新 4:更多测试(工作中)。在第三次转换到窗口模式后,钥匙挂钩肯定会被删除。它不再在键钩子方法内打印,并且无论按下哪个键都不会触发断点。我想我将就此提出一个单独的问题,因为我上面描述的所有其他问题只是这个关键钩子不调用 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 语句显示直到第 6 个 Alt+Enter 之后才调用关键钩子。这是第三次转换为窗口模式。我没有必要像我之前想的那样第四次进入全屏来导致问题。 MyClassVar 调用的所有方法都是内联的,以使键钩子尽可能快地运行,因为我知道 Windows 键钩子有超时。 Alt+Enter 的实际处理是由 MyClass 中的线程处理的。

另外,有人可以将其设为社区维基吗?我认为这个问题太具体了,无法用作维基。它成为其中之一的唯一原因是我一直在定期更新它并进行编辑。

SEE EDIT UPDATES BELOW. Original question has been modified!

I have a working window that uses a DX11 device. My problem comes along when I try to go fullscreen using Alt+Enter. If the window is not focused, i get a debug output that says:

'MyGame.exe': Loaded 'C:\Windows\SysWOW64\D3D10SDKLayers.DLL', Cannot find or open the PDB file

and then the warning

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

I'm fairly certain a DX11 game should NOT be loading D3D10SDKLayers.dll, especially during the middle of execution. From the MSDN docs, I gathered that this dll is loaded upon device creation: if a device is created with the appropriate layer flag, this DLL is loaded automatically. So i checked to see if my device creation methods were being called somehow during the middle of execution, and they are not. I only have 2 spots in my game where device creation exists, and neither spot is getting hit.
EDIT: after checking MSDN, it seems this dll is only a debug dll and might just be loaded to print out the warning itself, with no other purpose.

Explicit reproduction cases:

1) Alt+Enter 6 times (3 fullscreen transition cycles, both ways, starting windowed), on 7th the dll is loaded and the warning pops up. This happens regardless of window focusing.

Method Call Hierarchy Summary (going fullscreen):

1) ToggleFullscreen() - my method, only method called by Alt+Enter
2) ResizeTargetAndBuffers() - my method, sub-methods below
3) DXGISwapChain->ResizeTarget(frontBufferDesc) resizes front buffer to specified res
4) DXGISwapChain->GetFullscreenState() to determine fullscreen state
5) DXGISwapChain->SetFullscreenState(TRUE, NULL) to go fullscreen
6) ResizeDXGIBuffers(width, height, TRUE) my method, resizes back buffer, sub-method below
7) DXGISwapChain->ResizeBuffers(count, width, height, format, flags) to resize back buffer
8) DXGISwapChain->ResizeTarget(frontBufferDesc) prevents refresh rate issues. RefreshRate member zeroed out as per MSDN best practices.
9) DXGISwapChain->GetFullscreenState() to determine fullscreen state

Method Call Hierarchy Summary (going windowed):

1) ToggleFullscreen() - my method, only method called by Alt+Enter
2) ResizeTargetAndBuffers() - my method, sub-methods below
3) DXGISwapChain->ResizeTarget(backBufferDesc) resizes front buffer to specified res
4) DXGISwapChain->GetFullscreenState() to determine fullscreen state
5) DXGISwapChain->SetFullscreenState(FALSE, NULL) to go fullscreen
6) DXGISwapChain->ResizeTarget(backBufferDesc) to resize front buffer to window's res (helped resolve some res issues)
7) ResizeDXGIBuffers(width, height, FALSE) my method, resizes back buffer, sub-methods below
8) DXGISwapChain->ResizeBuffers(count, width, height, format, flags) to resize back buffer
9) DXGISwapChain->GetFullscreenState() to determine fullscreen state

The repercussions of this are quite severe. My low-level keyboard hook that catches Alt+Enter is no longer called, so windows is able to do its automatic Alt+Enter handling, which bypasses my ToggleFullscreen method entirely and sets the window to desktop resolution. This causes the buffers to be the wrong size (since I didn't set them, windows did), causing the inefficiency warning, and messing with the variables in my program which no longer have correct knowledge of buffer sizes and whether the window is fullscreen or not.

Any ideas as to what might be causing this?

P.S. If you need code samples be specific about what you want to see and I will try to put it up if possible. I can't put up the entire code listing.

EDIT: Device Creation code is below.


         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
                    );
                }

The first call succeeds 99% of the time, namely when you are not using remote desktop, so I will focus only on it. I give it the adapter, driverType as D3D_DRIVER_TYPE_HARDWARE, m_CreateFlags as D3D11_CREATE_DEVICE_DEBUG, and m_eFeatureLevel as D3D_FEATURE_LEVEL_11_0. Pretty standard call, and it always succeeds.

EDIT UPDATE 1: After some extensive debugging, I've found that when the dll is loaded and the inefficiency warning pops up, some very interesting circumstances arise. They are listed below:

1) VS2010 debugger no longer triggers breakpoints in the key hook.
2) Printed output no longer works in the key hook.
3) window may become non-re-sizable if it was re-sizable before
4) window may become un-movable.
5) a trio of threads exit.

EDIT UPDATE 2: The first edit update may have incorrect assumptions; if i find it does, i will delete it. It turns out that my low-level key hook is no longer being called (i think, since no breakpoints or print statements work inside of it), so if something in my program is unregistering it accidentally then that would cause all of the above problems. Testing this tomorrow...

EDIT UPDATE 3: I'm not sure what is going on anymore. I tested the same clean project on my home computer and work computer, and got different results. At home, I can Alt+Enter indefinitely without any problems occuring, but at work Alt+Enter the 7th time causes the key hook to no longer be called and the buffer problems to happen.

EDIT UPDATE 4: More testing (at work). The key hook is definitely being removed after the 3rd transition into windowed mode. It no longer prints inside the key hook method at all, and breakpoints are not triggered, regardless of what key is pressed. I think I'm going to open a separate question regarding this, as all the other problems I describe above are just consequences of this key hook not calling ToggleFullscreen(). For reference, I have provided the key hook code below.


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 );
    }
}

The printf statements show that the key hook is being called until right after the 6th Alt+Enter. This is the 3rd transition into windowed mode. It is not necessary for me to go fullscreen a 4th time, as I thought before, to cause the problem. All methods called by MyClassVar are inline to make the key hook go as fast as possible, as I know there is a timeout on windows key hooks. The actual processing of Alt+Enter is handled by a thread in MyClass.

Also, can someone make this not a community wiki? I think this question is far too specific to be of use as a wiki. The only reason it became one is I've been updating it regularly with edits.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

欲拥i 2025-01-03 23:13:25

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

I resolved this problem by taking out the key hook entirely. The proper way to handle Alt+Enter is to create your swap chain, then call IDXGIFactory1::MakeWindowAssosciation( m_hWnd, DXGI_MWA_NO_ALT_ENTER). Then you can handle Alt+Enter with your own code from your windows message procedure using WM_SYSKEYDOWN and WM_KEYUP. I hope this helps others! I had a hell of a time getting this to work, so if you are having a hard time getting it to work in your own app, send me a message and I'll try to help you!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文