Como renderizar usando um contexto de dispositivo Direct2D

Neste tópico, você aprenderá sobre a criação do contexto de dispositivo Direct2D no Windows 8. Essas informações se aplicarão a você se você estiver desenvolvendo aplicativos da Windows Store ou um aplicativo da área de trabalho usando o Direct2D. Este tópico descreve a finalidade dos objetos de contexto do dispositivo Direct2D, como criar esse objeto e um guia passo a passo sobre como renderizar e exibir primitivos e imagens do Direct2D. Você também aprenderá a alternar destinos de renderização e adicionar efeitos ao seu aplicativo.

O que é um dispositivo Direct2D?

Você precisa de um dispositivo Direct2D e um dispositivo Direct3D para criar um contexto de dispositivo Direct2D. Um dispositivo Direct2D (expõe um ponteiro de interface ID2D1Device) representa um adaptador de vídeo. Um dispositivo Direct3D (expõe um ponteiro de interface ID3D11Device) está associado a um dispositivo Direct2D. Cada aplicativo deve ter um dispositivo Direct2D, mas pode ter mais de um dispositivo.

O que é um contexto de dispositivo Direct2D?

Um contexto de dispositivo do Direct2D (expõe um ponteiro de interface ID2D1DeviceContext) representa um conjunto de buffers de estado e comando que você usa para renderizar em um destino. Você pode chamar métodos no contexto do dispositivo para definir o estado do pipeline e gerar comandos de renderização usando os recursos pertencentes a um dispositivo.

Renderização com o Direct2D no Windows 8

No Windows 7 e anteriores, você usa um ID2D1HwndRenderTarget ou outra interface de destino de renderização para renderizar em uma janela ou superfície. A partir do Windows 8, não recomendamos a renderização usando métodos que dependem de interfaces como ID2D1HwndRenderTarget porque eles não funcionarão com aplicativos da Windows Store. Você pode usar um contexto de dispositivo para renderizar em um Hwnd se quiser criar um aplicativo da área de trabalho e ainda aproveitar os recursos adicionais do contexto do dispositivo. No entanto, o contexto do dispositivo é necessário para renderizar conteúdo em aplicativos da Windows Store com o Direct2D.

Por que usar um contexto de dispositivo para renderizar?

Como criar um contexto de dispositivo Direct2D para renderização

O código aqui mostra como criar um dispositivo Direct3D11 e, por fim, criar o contexto de dispositivo do Direct2D para renderização.

Aqui está um diagrama das chamadas de método e das interfaces que esse código usa.

diagrama de dispositivos direct2d e direct3d e contextos de dispositivo.

Observação

Esse código pressupõe que você já tenha um objeto ID2D1Factory1, para obter mais informações, consulte a página de referência do ID2D1Factory.

 

    // This flag adds support for surfaces with a different color channel ordering than the API default.
    // You need it for compatibility with Direct2D.
    UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
    
    // This array defines the set of DirectX hardware feature levels this app  supports.
    // The ordering is important and you should  preserve it.
    // Don't forget to declare your app's minimum required feature level in its
    // description.  All apps are assumed to support 9.1 unless otherwise stated.
    D3D_FEATURE_LEVEL featureLevels[] = 
    {
        D3D_FEATURE_LEVEL_11_1,
        D3D_FEATURE_LEVEL_11_0,
        D3D_FEATURE_LEVEL_10_1,
        D3D_FEATURE_LEVEL_10_0,
        D3D_FEATURE_LEVEL_9_3,
        D3D_FEATURE_LEVEL_9_2,
        D3D_FEATURE_LEVEL_9_1
    };

    // Create the DX11 API device object, and get a corresponding context.
    ComPtr<ID3D11Device> device;
    ComPtr<ID3D11DeviceContext> context;

    DX::ThrowIfFailed(
        D3D11CreateDevice(
            nullptr,                    // specify null to use the default adapter
            D3D_DRIVER_TYPE_HARDWARE,
            0,                          
            creationFlags,              // optionally set debug and Direct2D compatibility flags
            featureLevels,              // list of feature levels this app can support
            ARRAYSIZE(featureLevels),   // number of possible feature levels
            D3D11_SDK_VERSION,          
            &device,                    // returns the Direct3D device created
            &m_featureLevel,            // returns feature level of device created
            &context                    // returns the device immediate context
            )
        );

    ComPtr<IDXGIDevice> dxgiDevice;
    // Obtain the underlying DXGI device of the Direct3D11 device.
    DX::ThrowIfFailed(
        device.As(&dxgiDevice)
        );

    // Obtain the Direct2D device for 2-D rendering.
    DX::ThrowIfFailed(
        m_d2dFactory->CreateDevice(dxgiDevice.Get(), &m_d2dDevice)
        );

    // Get Direct2D device's corresponding device context object.
    DX::ThrowIfFailed(
        m_d2dDevice->CreateDeviceContext(
            D2D1_DEVICE_CONTEXT_OPTIONS_NONE,
            &m_d2dContext
            )
        );

Vamos percorrer as etapas no exemplo de código anterior.

  1. Obtenha um ponteiro de interface ID3D11Device, você precisará dele para criar o contexto de dispositivo.

    • Declare os sinalizadores de criação para configurar o dispositivo Direct3D para suporte a BGRA. O Direct2D requer a ordem de cores BGRA.

    • Declare uma matriz de entradas D3D_FEATURE_LEVEL que representam o conjunto de níveis de recursos aos quais seu aplicativo dará suporte.

      Observação

      O Direct3D pesquisa sua lista até encontrar o nível de recurso com suporte pelo sistema host.

       

    • Use a função D3D11CreateDevice para criar um objeto ID3D11Device, a função retornará um objeto ID3D11DeviceContext, mas esse objeto não é necessário neste exemplo.

  2. Consulte o dispositivo Direct3D 11 para ver sua interface Dispositivo DXGI.

  3. Crie um objeto ID2D1Device chamando o método ID2D1Factory::CreateDevice e passando o objeto IDXGIDevice.

  4. Crie um ponteiro ID2D1DeviceContext usando o método ID2D1Device::CreateDeviceContext.

Seleção de um destino

O código aqui mostra como obter a textura bidimensional do Direct3D para o buffer de fundo da janela e crie um destino de bitmap que vincula a esses links para essa textura para a qual o contexto de dispositivo Direct2D é renderizado.

        // Allocate a descriptor.
        DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};
        swapChainDesc.Width = 0;                           // use automatic sizing
        swapChainDesc.Height = 0;
        swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // this is the most common swapchain format
        swapChainDesc.Stereo = false; 
        swapChainDesc.SampleDesc.Count = 1;                // don't use multi-sampling
        swapChainDesc.SampleDesc.Quality = 0;
        swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
        swapChainDesc.BufferCount = 2;                     // use double buffering to enable flip
        swapChainDesc.Scaling = DXGI_SCALING_NONE;
        swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // all apps must use this SwapEffect
        swapChainDesc.Flags = 0;

        // Identify the physical adapter (GPU or card) this device is runs on.
        ComPtr<IDXGIAdapter> dxgiAdapter;
        DX::ThrowIfFailed(
            dxgiDevice->GetAdapter(&dxgiAdapter)
            );

        // Get the factory object that created the DXGI device.
        ComPtr<IDXGIFactory2> dxgiFactory;
        DX::ThrowIfFailed(
            dxgiAdapter->GetParent(IID_PPV_ARGS(&dxgiFactory))
            );

        // Get the final swap chain for this window from the DXGI factory.
        DX::ThrowIfFailed(
            dxgiFactory->CreateSwapChainForCoreWindow(
                device.Get(),
                reinterpret_cast<IUnknown*>(m_window),
                &swapChainDesc,
                nullptr,    // allow on all displays
                &m_swapChain
                )
            );

        // Ensure that DXGI doesn't queue more than one frame at a time.
        DX::ThrowIfFailed(
            dxgiDevice->SetMaximumFrameLatency(1)
            );

    // Get the backbuffer for this window which is be the final 3D render target.
    ComPtr<ID3D11Texture2D> backBuffer;
    DX::ThrowIfFailed(
        m_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer))
        );

    // Now we set up the Direct2D render target bitmap linked to the swapchain. 
    // Whenever we render to this bitmap, it is directly rendered to the 
    // swap chain associated with the window.
    D2D1_BITMAP_PROPERTIES1 bitmapProperties = 
        BitmapProperties1(
            D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
            PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE),
            m_dpi,
            m_dpi
            );

    // Direct2D needs the dxgi version of the backbuffer surface pointer.
    ComPtr<IDXGISurface> dxgiBackBuffer;
    DX::ThrowIfFailed(
        m_swapChain->GetBuffer(0, IID_PPV_ARGS(&dxgiBackBuffer))
        );

    // Get a D2D surface from the DXGI back buffer to use as the D2D render target.
    DX::ThrowIfFailed(
        m_d2dContext->CreateBitmapFromDxgiSurface(
            dxgiBackBuffer.Get(),
            &bitmapProperties,
            &m_d2dTargetBitmap
            )
        );

    // Now we can set the Direct2D render target.
    m_d2dContext->SetTarget(m_d2dTargetBitmap.Get());

Vamos percorrer as etapas no exemplo de código anterior.

  1. Aloque uma estrutura DXGI_SWAP_CHAIN_DESC1 e defina as configurações para a cadeia de troca.

    Essas configurações mostram um exemplo de como criar uma cadeia de troca que um aplicativo da Windows Store pode usar.

  2. Obtenha o adaptador em que o Dispositivo Direct3D e o Dispositivo DXGI estão sendo executados e obtenha o objeto IDXGIFactory associado a eles. Você deve usar esta fábrica DXGI para garantir que a cadeia de troca seja criada no mesmo adaptador.

  3. Chame o método IDXGIFactory2::CreateSwapChainForCoreWindow para criar a cadeia de troca. Use a classe Windows::UI::CoreWindow para a janela principal de um aplicativo da Windows Store.

    Certifique-se de definir a latência máxima do quadro como 1 para minimizar o consumo de energia.

    Se você quiser renderizar conteúdo Direct2D em um aplicativo da Windows Store, consulte o método CreateSwapChainForComposition.

  4. Obtenha o buffer de fundo da cadeia de troca. O buffer traseiro expõe uma interface ID3D11Texture2D alocada pela cadeia de troca

  5. Declare uma struct D2D1_BITMAP_PROPERTIES1 e defina os valores de propriedade. Defina o formato de pixel como BGRA porque esse é o formato que o Dispositivo Direct3D e o Dispositivo DXGI usam.

  6. Obtenha o buffer de fundo como uma IDXGISurface para passar para Direct2D. Direct2D não aceita um ID3D11Texture2D diretamente.

    Crie um objeto ID2D1Bitmap do buffer de fundo usando o método ID2D1DeviceContext::CreateBitmapFromDxgiSurface.

  7. Agora, o bitmap do Direct2D está vinculado ao buffer de fundo. Defina o destino no contexto de dispositivo Direct2D para o bitmap.

Como renderizar e exibir

Agora que você tem um bitmap de destino, pode desenhar primitivos, imagens, efeitos de imagem e texto nele usando o contexto de dispositivo Direct2D. O código aqui mostra como desenhar um retângulo.

ComPtr<ID2D1SolidColorBrush> pBlackBrush;
DX::ThrowIfFailed(
   m_d2dContext->CreateSolidColorBrush(
        D2D1::ColorF(D2D1::ColorF::Black),
        &pBlackBrush
        )
);

m_d2dContext->BeginDraw();

m_d2dContext->DrawRectangle(
    D2D1::RectF(
        rc.left + 100.0f,
        rc.top + 100.0f,
        rc.right - 100.0f,
        rc.bottom - 100.0f),
        pBlackBrush);

DX::ThrowIfFailed(
    m_d2dContext->EndDraw()
);

DX::ThrowIfFailed(
    m_swapChain->Present1(1, 0, &parameters);
);

Vamos percorrer as etapas no exemplo de código anterior.

  1. Chame o CreateSolidColorBrush para criar um pincel para pintar o retângulo.
  2. Chame o método BeginDraw antes de emitir qualquer comando de desenho.
  3. Chame o método DrawRectangle do retângulo a ser desenhado e do pincel.
  4. Chame o método EndDraw depois de terminar de emitir comandos de desenho.
  5. Exiba o resultado chamando o método IDXGISwapChain::Present.

Agora você pode usar o contexto de dispositivo Direct2D para desenhar primitivos, imagens, efeitos de imagem e texto na tela.