通常,DirectX11初始化从创建DirectX11设备开始:

D3D_DRIVER_TYPE driverTypes[] =
{
    D3D_DRIVER_TYPE_HARDWARE,
    D3D_DRIVER_TYPE_WARP,
    D3D_DRIVER_TYPE_REFERENCE,
};

UINT nNumDriverTypes = ARRAYSIZE(driverTypes);

// Feature levels supported
D3D_FEATURE_LEVEL featureLevels[] =
{
    D3D_FEATURE_LEVEL_11_0,
    D3D_FEATURE_LEVEL_10_1,
    D3D_FEATURE_LEVEL_10_0,
    D3D_FEATURE_LEVEL_9_1
};

UINT nNumFeatureLevels = ARRAYSIZE(featureLevels);
D3D_FEATURE_LEVEL featureLevel;

// Create device
for (UINT n = 0; n < nNumDriverTypes; ++n)
{
    hr = D3D11CreateDevice(nullptr,driverTypes[n],nullptr, D3D11_CREATE_DEVICE_BGRA_SUPPORT,featureLevels,nNumFeatureLevels,
        D3D11_SDK_VERSION,&m_pDevice,&featureLevel,&m_pDeviceContext);

然后为窗口创建交换链:

IDXGIDevice* pDXGIDevice = nullptr;
HRESULT hr = m_pDevice->QueryInterface(__uuidof(IDXGIDevice),
    reinterpret_cast<void**>(&pDXGIDevice));
if (SUCCEEDED(hr))
{
    IDXGIAdapter* pDXGIAdapter = nullptr;
    hr = pDXGIDevice->GetParent(__uuidof(IDXGIAdapter),
        reinterpret_cast<void**>(&pDXGIAdapter));   
    if (SUCCEEDED(hr))
    {
        IDXGIFactory2* pDXGIFactory = nullptr;
        hr = pDXGIAdapter->GetParent(__uuidof(IDXGIFactory2),
            reinterpret_cast<void**>(&pDXGIFactory));
        if (SUCCEEDED(hr))
        {
            DXGI_SWAP_CHAIN_DESC1 desc = {};
            desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
            desc.BufferCount = 2;
            desc.Width = nWindowWidth;
            desc.Height = nWindowHeight;
            desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
            desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
            desc.SampleDesc.Count = 1;
            desc.SampleDesc.Quality = 0;        

            hr = pDXGIFactory->CreateSwapChainForHwnd(m_pDevice,hWnd,
                &desc,nullptr,nullptr,&m_pSwapChain);

我的电脑有两个连接到两个显示器的视频适配器.Adapter1Monitor1相连.Adapter2连接到Monitor2.我知道我可以枚举DXGI适配器,并使用特定的适配器for D3D11CreateDevice来创建DirectX11设备,但这对我没有帮助,因为我不知道哪个监视器显示我的窗口.

  • 如何找到显示窗口的显示器?我必须使用那个监视器视频适配器吗,还是可以使用任何适配器?
  • 如果用户将窗口从Monitor1移动到Monitor2,会发生什么?另一个适配器开始显示窗口了吗?
  • 总的来说,DirectX11如何处理这样的问题?

推荐答案

如果要创建与适配器匹配的设备,需要在调用中进行一些更改:

D3D11CreateDevice

我们的 idea 是自己提供适配器参数,因此过程是:

1/自己创建DXGI工厂,使用CreateDXGIFactory

2/列举该工厂的适配器,为此使用factory->EnumAdapters

3/对于每个适配器,您可以枚举连接到它们的监视器,adapter->EnumOutputs

4/然后可以使用output->GetDesc获取监视器描述

5/根据该描述,您可以访问屏幕边界,例如:

output_desc.DesktopCoordinates

现在,您可以使用窗口的边界并执行比较(最大区域、包含的…)

IDXGIAdapter* my_requested_adapter;
D3D11CreateDevice(my_requested_adapter, D3D_DRIVER_TYPE_UNKNOWN , nullptr, D3D11_CREATE_DEVICE_BGRA_SUPPORT,featureLevels,nNumFeatureLevels,
    D3D11_SDK_VERSION,&m_pDevice,&featureLevel,&m_pDeviceContext);

因此,调用中仅有的两个区别是,在函数的第一个参数中指定了请求的适配器,并且驱动程序类型变为D3D_driver_type_UNKNOWN(如果提供特定适配器,这是唯一有效的参数,因为驱动程序类型是从它推断出来的).

现在,如果用户将窗口移动到第二个显示器(连接到另一个图形卡),会发生什么情况?

最初,它将"神奇地工作",因为桌面窗口管理器(DWM)将检测到来自您窗口的内容需要显示在另一个图形卡上.

请注意,它还可能(将)增加延迟(我们有几个设置,多个窗口连接到不同的显示器,每个窗口使用一个设备连接到不同的GPU,它工作正常,但内容严重不同步(连接到另一个卡的显示器落后),因此我们必须确保使用两个设备,每张卡一张).

因此,如果您想确保始终使用最相关的适配器,则需要 for each 帧设置windows边界,如果窗口位于不同的适配器上,则需要使用该适配器创建一个新设备(当然,这需要重新创建在上一个适配器上创建的每个资源).

注:

还有一个函数名为:IDXGISwapChain::GetContainingOutput

C++相关问答推荐

从STdin读写超过4096个字节

自定义变参数函数的C预处置宏和警告 suppress ?

如何捕捉只有换行符或空格字符缓冲区的边缘大小写

判断X宏的空性

<;unistd.h>;和<;sys/unistd.h>;之间有什么区别?

添加函数会 destruct 嵌入式C代码(无IDE)

C语言中的外部关键字

是否定义了此函数的行为?

C语言中MPI发送接收字符串时出现的分段错误

递归打印二维数组(C编程)

如何将大写/小写土耳其字母相互转换?

对于STM32微控制器,全局偏移表.get和.Got.plt必须为零初始化

为什么我的二叉树删除删除整个左部分的树?

为什么GCC不能在 struct 初始值设定项中以sizeof作为条件的三进制中处理复合文字的编译时求值?

哪些C++功能可以在外部C块中使用

x86-64平台上的int_fast8_t大小与int_fast16_t大小

关于不同C编译器中的__attribute__支持

";错误:寄存器的使用无效;当使用-masm=intel;在gcc中,但在AT&;T模式

在列表中查找素数

使用替代日历打印日期