Inicializar o Direct3D 11
Resumo
- Parte 1: Inicializar o Direct3D 11
- Parte 2: Converter a estrutura de renderização
- Parte 3: Transferir o loop do jogo
Consulte como converter o código de inicialização do Direct3D 9 para usá-lo no Direct3D 11. Saiba também como obter identificadores para o dispositivo Direct3D e o contexto de dispositivo e como usar DXGI para configurar uma cadeia de troca. Parte 1 do passo a passo Portar um aplicativo Direct3D 9 simples para DirectX 11 e Plataforma Universal do Windows (UWP).
Inicializar o dispositivo Direct3D
No Direct3D 9, criamos um identificador para o dispositivo Direct3D chamando IDirect3D9::CreateDevice. Começamos obtendo um ponteiro para a interface IDirect3D9 e especificamos vários parâmetros para controlar a configuração do dispositivo Direct3D e a cadeia de troca. Antes de fazer isso, ligamos para GetDeviceCaps para garantir que não estávamos pedindo ao dispositivo para fazer algo que ele não podia fazer.
Direct3D 9
UINT32 AdapterOrdinal = 0;
D3DDEVTYPE DeviceType = D3DDEVTYPE_HAL;
D3DCAPS9 caps;
m_pD3D->GetDeviceCaps(AdapterOrdinal, DeviceType, &caps); // caps bits
D3DPRESENT_PARAMETERS params;
ZeroMemory(¶ms, sizeof(D3DPRESENT_PARAMETERS));
// Swap chain parameters:
params.hDeviceWindow = m_hWnd;
params.AutoDepthStencilFormat = D3DFMT_D24X8;
params.BackBufferFormat = D3DFMT_X8R8G8B8;
params.MultiSampleQuality = D3DMULTISAMPLE_NONE;
params.MultiSampleType = D3DMULTISAMPLE_NONE;
params.SwapEffect = D3DSWAPEFFECT_DISCARD;
params.Windowed = true;
params.PresentationInterval = 0;
params.BackBufferCount = 2;
params.BackBufferWidth = 0;
params.BackBufferHeight = 0;
params.EnableAutoDepthStencil = true;
params.Flags = 2;
m_pD3D->CreateDevice(
0,
D3DDEVTYPE_HAL,
m_hWnd,
64,
¶ms,
&m_pd3dDevice
);
No Direct3D 11, o contexto do dispositivo e a infraestrutura gráfica são considerados separados do próprio dispositivo. A inicialização é dividida em várias etapas.
Primeiro criamos o dispositivo. Obtemos uma lista dos níveis de recursos que o dispositivo suporta - isso informa a maior parte do que precisamos saber sobre a GPU. Além disso, não precisamos criar uma interface apenas para acessar o Direct3D. Em vez disso, usamos a API principal D3D11CreateDevice . Isso nos dá uma alça para o dispositivo e o contexto imediato do dispositivo. O contexto do dispositivo é usado para definir o estado do pipeline e gerar comandos de renderização.
Depois de criar o dispositivo e o contexto do Direct3D 11, podemos aproveitar a funcionalidade do ponteiro COM para obter a versão mais recente das interfaces, que incluem recursos adicionais e são sempre recomendadas.
Observação D3D_FEATURE_LEVEL_9_1 (que corresponde ao modelo de sombreador 2.0) é o nível mínimo que seu jogo da Microsoft Store deve dar suporte. (Os pacotes Arm do seu jogo falharão na certificação se você não for compatível com 9_1.) Se o jogo também incluir um caminho de renderização para recursos do modelo de sombreador 3, você deverá incluir D3D_FEATURE_LEVEL_9_3 na matriz.
Direct3D 11
// This flag adds support for surfaces with a different color channel
// ordering than the API default. It is required for compatibility with
// Direct2D.
UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
#if defined(_DEBUG)
// If the project is in a debug build, enable debugging via SDK Layers.
creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
// This example only uses feature level 9.1.
D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_9_1
};
// Create the Direct3D 11 API device object and a corresponding context.
ComPtr<ID3D11Device> device;
ComPtr<ID3D11DeviceContext> context;
D3D11CreateDevice(
nullptr, // Specify nullptr to use the default adapter.
D3D_DRIVER_TYPE_HARDWARE,
nullptr,
creationFlags,
featureLevels,
ARRAYSIZE(featureLevels),
D3D11_SDK_VERSION, // UWP apps must set this to D3D11_SDK_VERSION.
&device, // Returns the Direct3D device created.
nullptr,
&context // Returns the device immediate context.
);
// Store pointers to the Direct3D 11.2 API device and immediate context.
device.As(&m_d3dDevice);
context.As(&m_d3dContext);
Criar uma cadeia de troca
O Direct3D 11 inclui uma API de dispositivo chamada DXGI (infraestrutura gráfica DirectX). A interface DXGI nos permite (por exemplo) controlar como a cadeia de troca é configurada e configurar dispositivos compartilhados. Nesta etapa da inicialização do Direct3D, usaremos o DXGI para criar uma cadeia de troca. Como criamos o dispositivo, podemos seguir uma cadeia de interface de volta ao adaptador DXGI.
O dispositivo Direct3D implementa uma interface COM para DXGI. Primeiro, precisamos obter essa interface e usá-la para solicitar o adaptador DXGI que hospeda o dispositivo. Em seguida, usamos o adaptador DXGI para criar uma fábrica DXGI.
Observação Essas são interfaces COM, portanto, sua primeira resposta pode ser usar QueryInterface. Em vez disso, você deve usar ponteiros inteligentes Microsoft::WRL::ComPtr. Em seguida, basta chamar o método As(), fornecendo um ponteiro COM vazio do tipo de interface correto.
Direct3D 11
ComPtr<IDXGIDevice2> dxgiDevice;
m_d3dDevice.As(&dxgiDevice);
// Then, the adapter hosting the device;
ComPtr<IDXGIAdapter> dxgiAdapter;
dxgiDevice->GetAdapter(&dxgiAdapter);
// Then, the factory that created the adapter interface:
ComPtr<IDXGIFactory2> dxgiFactory;
dxgiAdapter->GetParent(
__uuidof(IDXGIFactory2),
&dxgiFactory
);
Agora que temos a fábrica DXGI, podemos usá-la para criar a cadeia de troca. Vamos definir os parâmetros da cadeia de troca. Precisamos especificar o formato da superfície; escolheremos DXGI_FORMAT_B8G8R8A8_UNORM porque é compatível com Direct2D. Desativaremos o dimensionamento de exibição, a multiamostragem e a renderização estéreo porque eles não são usados neste exemplo. Como estamos executando diretamente em um CoreWindow, podemos deixar a largura e a altura definidas como 0 e obter valores de tela cheia automaticamente.
Observação Sempre defina o parâmetro SDKVersion como D3D11_SDK_VERSION para aplicativos UWP.
Direct3D 11
ComPtr<IDXGISwapChain1> swapChain;
dxgiFactory->CreateSwapChainForCoreWindow(
m_d3dDevice.Get(),
reinterpret_cast<IUnknown*>(window),
&swapChainDesc,
nullptr,
&swapChain
);
swapChain.As(&m_swapChain);
Para garantir que não estamos renderizando com mais frequência do que a tela pode realmente exibir, definimos a latência do quadro como 1 e usamos DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL. Isso economiza energia e é um requisito de certificação da loja; Aprenderemos mais sobre como apresentar na tela na Parte 2 deste passo a passo.
Observação Você pode usar multithreading (por exemplo, itens de trabalho ThreadPool ) para continuar outro trabalho enquanto o thread de renderização está bloqueado.
Direct3D 11
dxgiDevice->SetMaximumFrameLatency(1);
Agora podemos configurar o buffer traseiro para renderização.
Configurar o buffer traseiro como um destino de renderização
Primeiro temos que obter uma alça para o buffer traseiro. (Observe que o buffer traseiro pertence à cadeia de troca DXGI, enquanto no DirectX 9 ele pertencia ao dispositivo Direct3D.) Em seguida, informamos ao dispositivo Direct3D para usá-lo como o destino de renderização criando uma exibição de destino de renderização usando o buffer traseiro.
Direct3D 11
ComPtr<ID3D11Texture2D> backBuffer;
m_swapChain->GetBuffer(
0,
__uuidof(ID3D11Texture2D),
&backBuffer
);
// Create a render target view on the back buffer.
m_d3dDevice->CreateRenderTargetView(
backBuffer.Get(),
nullptr,
&m_renderTargetView
);
Agora o contexto do dispositivo entra em jogo. Dizemos ao Direct3D para usar nossa exibição de destino de renderização recém-criada usando a interface de contexto do dispositivo. Recuperaremos a largura e a altura do buffer traseiro para que possamos direcionar toda a janela como nossa janela de visualização. Observe que o buffer traseiro está conectado à cadeia de troca, portanto, se o tamanho da janela mudar (por exemplo, o usuário arrasta a janela do jogo para outro monitor), o buffer traseiro precisará ser redimensionado e algumas configurações precisarão ser refeitas.
Direct3D 11
D3D11_TEXTURE2D_DESC backBufferDesc = {0};
backBuffer->GetDesc(&backBufferDesc);
CD3D11_VIEWPORT viewport(
0.0f,
0.0f,
static_cast<float>(backBufferDesc.Width),
static_cast<float>(backBufferDesc.Height)
);
m_d3dContext->RSSetViewports(1, &viewport);
Agora que temos um identificador de dispositivo e um destino de renderização em tela cheia, estamos prontos para carregar e desenhar geometria. Continue para a Parte 2: Renderização.