English 中文(简体)
每个监视器直接X 10 显示不同的图像
原标题:Display Different images per monitor directX 10

我对DirectX 10编程相当新, 我一直试图用我有限的技能来做以下工作(虽然我与OpenGL有着很强的背景背景)

我试图显示两个不同的纹理 Quads, 每个显示器一个。 为此, 我理解我需要一个 D3D10 设备, 多(2) 互换链, 以及一个 VertexBuffer

虽然我认为我能够创造所有这些,但我仍然不太确定如何处理所有这些。我是否需要多个 ID3D10Render Target View?我应该如何和在哪里使用 OMSetRender Tablets (...)?

除了MSDN之外,关于这些概念的文件或解释相当有限,因此非常欢迎任何帮助。

这里的创建代码

for(int i = 0; i < screenNumber; i++){
    //clear scene
    pD3DDevice->ClearRenderTargetView( pRenderTargetView, D3DXCOLOR(0,1,0,0) );

    //fill vertex buffer with vertices
    UINT numVertices = 4;   
    vertex* v = NULL;   

    //lock vertex buffer for CPU use
    pVertexBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**) &v );

    v[0] = vertex( D3DXVECTOR3(-1,-1,0), D3DXVECTOR4(1,0,0,1), D3DXVECTOR2(0.0f, 1.0f) );
    v[1] = vertex( D3DXVECTOR3(-1,1,0), D3DXVECTOR4(0,1,0,1), D3DXVECTOR2(0.0f, 0.0f) );
    v[2] = vertex( D3DXVECTOR3(1,-1,0), D3DXVECTOR4(0,0,1,1), D3DXVECTOR2(1.0f, 1.0f) );
    v[3] = vertex( D3DXVECTOR3(1,1,0), D3DXVECTOR4(1,1,0,1), D3DXVECTOR2(1.0f, 0.0f) ); 

    pVertexBuffer->Unmap();

    // Set primitive topology 
    pD3DDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP );

    //set texture
    pTextureSR->SetResource( textureSRV[textureIndex] );

    //get technique desc
    D3D10_TECHNIQUE_DESC techDesc;
    pBasicTechnique->GetDesc( &techDesc );


    // This is where you actually use the shader code
    for( UINT p = 0; p < techDesc.Passes; ++p )
    {
        //apply technique
        pBasicTechnique->GetPassByIndex( p )->Apply( 0 );

        //draw
        pD3DDevice->Draw( numVertices, 0 );
    时 时

    //flip buffers
    pSwapChain[i]->Present(0,0);
时 时

下面是设定目标的代码, 我不确定它是否好

for(int i = 0; i < screenNumber; ++i){

    //try to get the back buffer
    ID3D10Texture2D* pBackBuffer;   
    if ( FAILED( pSwapChain[1]->GetBuffer(0, __uuidof(ID3D10Texture2D), (LPVOID*) &pBackBuffer) ) ) return fatalError("Could not get back buffer");

    //try to create render target view
    if ( FAILED( pD3DDevice->CreateRenderTargetView(pBackBuffer, NULL, &pRenderTargetView) ) ) return fatalError("Could not create render target view");

    pBackBuffer->Release();
    pD3DDevice->OMSetRenderTargets(1, &pRenderTargetView, NULL);
时 时

return true;

时 时

最佳回答

我希望我能了解你们想要做什么——在两个不同的显示器上提供不同的内容,同时使用一张图形卡片(图形调整器),该卡片将输出映射为这些显示器。为此,你们需要一台设备(用于单个图形卡片/适应器),并列出用户机器中有多少输出。

所以,总而言之,这意味着一个装置,两个输出,两个窗口,因此,两个互换链。

下面是我的小实验的一个快速结果:

"https://i.sstatic.net/oLele.jpg" alt="结果"/ >

A little introduction

在DirectX10+中,这属于DXGI(DirectX图形基础设施)(DirectX图形基础设施),它管理着与DirectX 10+开发有关的普通低水平物流,而正如你可能知道的那样,DXGI(DirectX 图形基础设施)抛弃了列举地物组的旧要求和类似要求,要求每个DX10+有能力的卡片分享API定义的所有特征。唯一不同的是卡片的范围和能力(换句话说,不良性能优于应用程序的崩溃和燃烧) 。这过去都在DirX 9范围内,但微软公司的人决定把它拉出来,称为DXGI。现在,我们可以使用DXGI的功能来设置我们的多监视环境。

我需要多重 ID3D10Render TagetView(s) 吗?

是的, 您确实需要多个化成目标视图, 计数取决于您拥有的显示器数量( 如交换链和窗口) 。 但是, 为了避免您使用扭曲的单词, 请尽可能简单地写出来, 并在需要时提供补充信息 :

  • Enumerate all adapters available on the system.
  • For each adapter, enumerate all outputs available (and active) and create a device to accompany it.
  • With the enumerated data stored in a suitable structure (think arrays which can quickly relinquish size information), use it to create n windows, swap chains, render target views, depth/stencil textures and their respective views where n is equal to the number of outputs.
  • With everything created, for each window you are rendering into, you can define special routines which will use the available geometry (and other) data to output your results - which resolves to what each monitor gets in fullscreen (don t forget to adjust the viewport for every window accordingly).
  • Present your data by iterating over every swap chain which is linked to its respective window and swap buffers with Present()

虽然这在字数上是丰富的, 但有些代码的价值要多得多。 设计这个代码是为了让您粗略地了解一个简单的多监测器应用程序的实施过程。 因此, 假设是只有一个适配器( 比较大胆的语句) 和多个输出 - 没有故障保险。 我将让您来做有趣的部分 。 “ 强大的” 第二个问题在楼下...

Do note there no memory management without. 我们假设所有的东西在不需要用于插图时都会被神奇地清理干净。 成为良好的记忆公民 。

< 强 > 获取适配器

IDXGIAdapter* adapter = NULL;
void GetAdapter() // applicable for multiple ones with little effort
{
    // remember, we assume there s only one adapter (example purposes)
    for( int i = 0; DXGI_ERROR_NOT_FOUND != factory->EnumAdapters( i, &adapter ); ++i )
    {

        // get the description of the adapter, assuming no failure
        DXGI_ADAPTER_DESC adapterDesc;
        HRESULT hr = adapter->GetDesc( &adapterDesc );

        // Getting the outputs active on our adapter
        EnumOutputsOnAdapter();

}

< 强 > 获取我们的适配器 < /强 > 的输出

std::vector<IDXGIOutput*> outputArray; // contains outputs per adapter
void EnumOutputsOnAdapter()
{
    IDXGIOutput* output = NULL;
    for(int i = 0; DXGI_ERROR_NOT_FOUND != adapter->EnumOutputs(i, &output); ++i)
    {

        // get the description
        DXGI_OUTPUT_DESC outputDesc;
        HRESULT hr = output->GetDesc( &outputDesc );

        outputArray.push_back( output );
    }

}

现在,我必须假设,你至少知道Win32 API的考虑, 创建窗口班, 与系统注册, 创建窗口等等... 因此,我将不限定它的创建, 只阐述它与多个窗口的关系。 另外,我在这里只考虑全屏案例, 但以窗口模式创建它不仅仅是可能的, 而且相当微不足道 。

< 强 > 为我们输出 创建实际窗口 < /强 >

由于我们假设只有一个适配器,我们只考虑与该特定适配器相联系的所列举的产出。 最好将所有窗口数据组织成简洁的小型结构,但为了这个答案的目的,我们只是把它们推入一个简单的支架中,然后放入另一个 std::矢量天体,用它们来说,我是指对各自窗口(HWND)及其大小(尽管就我们的情况而言,它保持不变)进行控制。

但是,我们仍然必须解决一个事实,即我们有一个互换链,一个让目标视图,每个窗口一个深度/高度视图。那么,为什么不在描述我们每个窗口的小支架中喂食所有这些东西呢?这有道理,对吧?

struct WindowDataContainer
{
    //Direct3D 10 stuff per window data
    IDXGISwapChain* swapChain;
    ID3D10RenderTargetView* renderTargetView;
    ID3D10DepthStencilView* depthStencilView;

    // window goodies
    HWND hWnd;
    int width;
    int height;
}

不错,其实不是,但是...

std::vector<WindowDataContainer*> windowsArray;
void CreateWindowsForOutputs()
{
    for( int i = 0; i < outputArray.size(); ++i )
    {

        IDXGIOutput* output = outputArray.at(i);
        DXGI_OUTPUT_DESC outputDesc;
        p_Output->GetDesc( &outputDesc );
        int x = outputDesc.DesktopCoordinates.left;
        int y = outputDesc.DesktopCoordinates.top;
        int width = outputDesc.DesktopCoordinates.right - x;
        int height = outputDesc.DesktopCoordinates.bottom - y;

        // Don t forget to clean this up. And all D3D COM objects.
        WindowDataContainer* window = new WindowDataContainer;

        window->hWnd = CreateWindow( windowClassName,
                                        windowName,
                                        WS_POPUP,
                                        x,
                                        y,
                                        width,
                                        height,
                                        NULL,
                                        0,
                                        instance,
                                        NULL );

        // show the window
        ShowWindow( window->hWnd, SW_SHOWDEFAULT );

        // set width and height
        window->width = width;
        window->height = height;

        // shove it in the std::vector
        windowsArray.push_back( window );

        //if first window, associate it with DXGI so it can jump in
        // when there is something of interest in the message queue
        // think fullscreen mode switches etc. MSDN for more info.
        if(i == 0)
            factory->MakeWindowAssociation( window->hWnd, 0 );

    }
}

太可爱了。因为我们只有一台适配器,因此只有一台设备可以随身携带,所以,我们照常创建它。就我而言,它只是一个全球界面指示器,可以到处访问。我们不会在这里获取年度代码,所以为什么没有呢?

< 强 > 创建互换链、视图和深度/ 高级 2D 纹理

现在,我们友好的互换链... 你可能会习惯于通过援引“裸装”函数 D3D10Create DeviceandSwapchain (...) , (...) ,但你知道,我们已经制造了我们的设备。 我们只想要一个。 还有多个互换链。 嗯,这是一个泡菜。 幸运的是, 我们的DXGIFactory界面在其生产线上设置了互换链条, 我们可以免费接收补充朗姆酒。 然后, 在互换链条上, 为每个窗口创建 :

void CreateSwapChainsAndViews()
{
    for( int i = 0; i < windowsArray.size(); i++ )
    {
        WindowDataContainer* window = windowsArray.at(i);

        // get the dxgi device
        IDXGIDevice* DXGIDevice = NULL;
        device->QueryInterface( IID_IDXGIDevice, ( void** )&DXGIDevice ); // COM stuff, hopefully you are familiar

        // create a swap chain
        DXGI_SWAP_CHAIN_DESC swapChainDesc;
        
        // fill it in

        HRESULT hr = factory->CreateSwapChain( DXGIDevice, &swapChainDesc, &p_Window->swapChain );
        DXGIDevice->Release();
        DXGIDevice = NULL;

         // get the backbuffer
        ID3D10Texture2D* backBuffer = NULL;
        hr = window->swapChain->GetBuffer( 0, IID_ID3D10Texture2D, ( void** )&backBuffer );

        // get the backbuffer desc
        D3D10_TEXTURE2D_DESC backBufferDesc;
        backBuffer->GetDesc( &backBufferDesc );

        // create the render target view
        D3D10_RENDER_TARGET_VIEW_DESC RTVDesc;

        // fill it in

        device->CreateRenderTargetView( backBuffer, &RTVDesc, &window->renderTargetView );
        backBuffer->Release();
        backBuffer = NULL;

        // Create depth stencil texture
        ID3D10Texture2D* depthStencil = NULL;
        D3D10_TEXTURE2D_DESC descDepth;

        // fill it in


        device->CreateTexture2D( &descDepth, NULL, &depthStencil );

        // Create the depth stencil view
        D3D10_DEPTH_STENCIL_VIEW_DESC descDSV;

        // fill it in

        device->CreateDepthStencilView( depthStencil, &descDSV, &window->depthStencilView );

    }

}

我们现在拥有我们所需要的一切。你需要做的就是定义一个功能, 在所有窗口上循环, 并适当绘制不同的东西。

我应如何和在哪里使用 OMSetRender 目标(...)?

在上述功能中,所有窗口都循环并使用适当的设定目标(我们每个窗口数据容器的价值):

void MultiRender( )
{
    // Clear them all
    for( int i = 0; i < windowsArray.size(); i++ )
    {
        WindowDataContainer* window = windowsArray.at(i);

        // There is the answer to your second question:
        device->OMSetRenderTargets( 1, &window->renderTargetView, window->depthStencilView );

        // Don t forget to adjust the viewport, in fullscreen it s not important...
        D3D10_VIEWPORT Viewport;
        Viewport.TopLeftX = 0;
        Viewport.TopLeftY = 0;
        Viewport.Width = window->width;
        Viewport.Height = window->height;
        Viewport.MinDepth = 0.0f;
        Viewport.MaxDepth = 1.0f;
        device->RSSetViewports( 1, &Viewport );

        // TO DO: AMAZING STUFF PER WINDOW
    }
}

当然, 不要忘了运行所有互换链和每个窗口的缓冲。 这里的代码只是为了这个答案的目的, 它需要多做点工作, 检查错误( 错误安全) 和考虑才能让它按照你喜欢的方式运作, 换句话说, 它应该给你一个简化的概览, 而不是一个生产解决方案 。

祝你好运和好运!

问题回答

暂无回答




相关问题
Undefined reference

I m getting this linker error. I know a way around it, but it s bugging me because another part of the project s linking fine and it s designed almost identically. First, I have namespace LCD. Then I ...

C++ Equivalent of Tidy

Is there an equivalent to tidy for HTML code for C++? I have searched on the internet, but I find nothing but C++ wrappers for tidy, etc... I think the keyword tidy is what has me hung up. I am ...

Template Classes in C++ ... a required skill set?

I m new to C++ and am wondering how much time I should invest in learning how to implement template classes. Are they widely used in industry, or is this something I should move through quickly?

Print possible strings created from a Number

Given a 10 digit Telephone Number, we have to print all possible strings created from that. The mapping of the numbers is the one as exactly on a phone s keypad. i.e. for 1,0-> No Letter for 2->...

typedef ing STL wstring

Why is it when i do the following i get errors when relating to with wchar_t? namespace Foo { typedef std::wstring String; } Now i declare all my strings as Foo::String through out the program, ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

Window iconification status via Xlib

Is it possible to check with the means of pure X11/Xlib only whether the given window is iconified/minimized, and, if it is, how?