zer*_*mes 5 c++ directx multiple-monitors
我是DirectX 10编程的新手,我一直在尝试用我有限的技能做以下事情(尽管我有很强的OpenGL背景)
我试图显示2个不同的纹理四边形,每个显示器1个.为此,我明白我需要一个D3D10设备,多个(2)交换链和单个VertexBuffer
虽然我认为我能够创造所有这些,但我仍然不确定如何处理所有这些.我需要多个ID3D10RenderTargetView吗?我应该如何以及在哪里使用OMSetRenderTargets(...)?
除了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);
}
Run Code Online (Sandbox Code Playgroud)
这里是创建渲染目标的代码,我不确定它是好的
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;
Run Code Online (Sandbox Code Playgroud)
}
小智 30
我希望得到你想做的事情的要点 - 在使用单个图形卡(图形适配器)的同时在两个不同的显示器上呈现不同的内容,将其输出映射到这些显示器.为此,您将需要一个设备(用于单个图形卡/适配器)并枚举用户机器上的输出数量.
因此,总的来说 - 这意味着一个设备,两个输出,两个窗口,因此 - 两个交换链.
这是我的小实验的快速结果:

使用DirectX 10+,这属于DXGI(DirectX图形基础设施),它管理与DirectX 10+开发相关的常见低级物流,正如您可能知道的那样,抛弃了枚举功能集等的旧要求 - 需要每个支持DX10 +的卡可以共享API定义的所有功能.唯一不同的是卡的范围和能力(换句话说,糟糕的性能比应用程序崩溃和刻录更好).这一切都在DirectX 9中,但微软的人们决定将其推出并称之为DXGI.现在,我们可以使用DXGI功能来设置我们的多监视器环境.
我需要多个ID3D10RenderTargetView吗?
是的,您确实需要多个渲染目标视图,count依赖于(如交换链和窗口)您拥有的监视器数量.但是,为了避免喷出单词,让我们尽可能简单地写出来并在需要的地方添加其他信息:
现在,虽然字数很丰富,但有些代码值得更多.这旨在让您大致了解实现简单多监视器应用程序的内容.因此,假设只有一个适配器(现在是一个相当大胆的声明)和多个输出 - 并且没有故障.我会把有趣的部分留给你.回答第二个问题是在楼下......
请注意,不涉及内存管理.我们假设在出于说明目的不需要时,所有内容都会被神奇地清理干净.做个好记忆的公民.
获得适配器
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();
}
Run Code Online (Sandbox Code Playgroud)
获取适配器上的输出
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 );
}
}
Run Code Online (Sandbox Code Playgroud)
现在,我必须假设你至少知道Win32 API的注意事项,创建窗口类,注册系统,创建窗口等等......因此,我不会限定它的创建,只详细说明它是如何属于多个视窗.此外,我将仅考虑全屏大小写,但在窗口模式下创建它不仅可能而且非常简单.
为我们的输出创建实际窗口
由于我们假设只存在一个适配器,我们只考虑链接到该特定适配器的枚举输出.最好用简洁的小结构组织所有窗口数据,但是为了这个答案的目的,我们只是把它们推到一个简单的结构中然后再转移到另一个std :: vector对象中,我用它们来表示句柄各个窗口(HWND)及其大小(虽然对于我们的情况它是恒定的).
但是,我们必须解决这样一个事实:我们有一个交换链,一个渲染目标视图,每个窗口一个深度/模板视图.那么,为什么不在描述我们每个窗口的那个小结构中提供所有这些呢?有道理,对吗?
struct WindowDataContainer
{
//Direct3D 10 stuff per window data
IDXGISwapChain* swapChain;
ID3D10RenderTargetView* renderTargetView;
ID3D10DepthStencilView* depthStencilView;
// window goodies
HWND hWnd;
int width;
int height;
}
Run Code Online (Sandbox Code Playgroud)
尼斯.好吧,不是真的.但仍然......继续前进!现在为输出创建窗口:
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 );
}
}
Run Code Online (Sandbox Code Playgroud)
可爱,现在已经完成了.由于我们只有一个适配器,因此只有一个设备可以随身携带,所以请照常创建.就我而言,它只是一个全局接口指针,可以在任何地方访问.我们不打算在这里找到年度代码,所以为什么不呢,呃?
创建交换链,视图和深度/模板2D纹理
现在,我们友好的交换链......您可能习惯于通过调用"裸"函数来实际创建它们D3D10CreateDeviceAndSwapChain(...),但是如您所知,我们已经制作了我们的设备.我们只想要一个.和多个交换链.嗯,这是一个泡菜.幸运的是,我们的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 );
}
}
Run Code Online (Sandbox Code Playgroud)
我们现在拥有我们需要的一切.您需要做的就是定义一个函数,它迭代所有窗口并适当地绘制不同的东西.
我应该如何以及在哪里使用OMSetRenderTargets(...)?
在刚才提到的函数中,迭代所有窗口并使用适当的渲染目标(由我们的每个窗口数据容器提供):
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
}
}
Run Code Online (Sandbox Code Playgroud)
当然,不要忘记每个窗口运行所有交换链和交换缓冲区.这里的代码只是为了这个答案的目的,它需要更多的工作,错误检查(failsafes)和沉思,让它以你喜欢的方式工作 - 换句话说 - 它应该给你一个简化的概述,而不是生产解决方案.
祝你好运,编码愉快!Sheesh,这是巨大的.
| 归档时间: |
|
| 查看次数: |
4830 次 |
| 最近记录: |