Compartilhar via


Inicializar o Direct3D 11

Resumo

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(&params, 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,
    &params,
    &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.