Partager via


Comment effectuer un rendu en utilisant un contexte d'appareil Direct2D

Dans cette rubrique, vous apprendrez à créer un contexte d'appareil Direct2D dans Windows 8. Ces informations vous concernent si vous développez des applications Windows Store ou une application de bureau en utilisant Direct2D. Cette rubrique décrit l'objectif des objets de contexte d'appareil Direct2D, comment créer cet objet, et un guide étape par étape sur le rendu et l'affichage des primitives et des images Direct2D. Vous apprendrez également à changer de cible de rendu et à ajouter des effets à votre application.

Qu'est-ce qu'un appareil Direct2D ?

Vous devez disposer d'un appareil Direct2D et d'un appareil Direct3D pour créer un contexte d'appareil Direct2D. Un appareil Direct2D (expose un pointeur d'interface ID2D1Device) représente un adaptateur d'affichage. Un appareil Direct3D (expose un pointeur d'interface ID3D11Device) est associé à un appareil Direct2D. Chaque application doit avoir un appareil Direct2D, mais peut en avoir plusieurs.

Qu'est-ce qu'un contexte d'appareil Direct2D ?

Un contexte d'appareil Direct2D (expose un pointeur d'interface ID2D1DeviceContext) représente un ensemble de tampons d'état et de commande que vous utilisez pour effectuer un rendu vers une cible. Vous pouvez appeler des méthodes sur le contexte de l'appareil pour définir l'état du pipeline et générer des commandes de rendu en utilisant les ressources appartenant à un appareil.

Rendu avec Direct2D sur Windows 8

Sous Windows 7 et les versions antérieures, vous utilisez une ID2D1HwndRenderTarget ou une autre interface de cible de rendu pour effectuer un rendu sur une fenêtre ou une surface. À partir de Windows 8, nous ne recommandons pas d'effectuer le rendu en utilisant des méthodes qui reposent sur des interfaces telles que ID2D1HwndRenderTarget, car elles ne fonctionneront pas avec les applications du Windows Store. Vous pouvez utiliser un contexte d'appareil pour effectuer un rendu vers un Hwnd si vous souhaitez créer une application de bureau tout en profitant des fonctionnalités supplémentaires du contexte d'appareil. Cependant, le contexte de l'appareil est nécessaire pour rendre le contenu d'une application Windows Store avec Direct2D.

Pourquoi utiliser un contexte d'appareil pour effectuer un rendu ?

  • Vous pouvez effectuer le rendu pour les applications du Windows Store.
  • Vous pouvez modifier la cible de rendu à tout moment avant, pendant et après le rendu. Le contexte d'appareil garantit que les appels aux méthodes de dessin sont exécutés dans l'ordre et les applique lorsque vous changez de cible de rendu.
  • Vous pouvez utiliser plusieurs types de fenêtres avec un contexte d'appareil. Vous pouvez utiliser un contexte d'appareil et une chaîne d'échange DXGI pour effectuer un rendu directement sur une Windows::UI::Core::CoreWindow ou une Windows::UI::XAML::SwapChainBackgroundPanel.
  • Vous pouvez utiliser le contexte de l'appareil Direct2D pour créer des effets Direct2D et pour effectuer le rendu de la sortie d'un effet d'image ou d'un graphe d'effet vers une cible de rendu.
  • Vous pouvez avoir plusieurs contextes d'appareil, ce qui peut être utile pour améliorer les performances dans une application threading. Pour plus d'informations, reportez-vous à la section Applications Direct2D multithreadées.
  • Le contexte d'appareil interagit étroitement avec Direct3D, ce qui vous permet d'accéder plus facilement aux options Direct3D.

Comment créer un contexte d'appareil Direct2D pour le rendu

Le code ci-dessous vous montre comment créer un appareil Direct3D11, obtenir l'appareil DXGI associé, créer un appareil Direct2D et enfin créer le contexte d'appareil Direct2D pour le rendu.

Voici un diagramme des appels de méthode et des interfaces que ce code utilise.

diagramme des appareils direct2d et direct3d et des contextes d'appareil.

Remarque

Ce code suppose que vous avez déjà un objet ID2D1Factory1, pour plus d'informations voir la page de référence 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
            )
        );

Passons en revue les étapes de l'exemple de code précédent.

  1. Obtenez un pointeur d'interface ID3D11Device, vous en aurez besoin pour créer le contexte de l'appareil.

    • Déclarez les indicateurs de création pour configurer l'appareil Direct3D pour la prise en charge du BGRA. Direct2D requiert l'ordre des couleurs BGRA.

    • Déclarez un tableau d'entrées D3D_FEATURE_LEVEL représentant l'ensemble des niveaux de fonctionnalité que votre application prendra en charge.

      Remarque

      Direct3D recherche votre liste jusqu'à ce qu'il trouve le niveau de fonctionnalité pris en charge par le système hôte.

       

    • Utilisez la fonction D3D11CreateDevice pour créer un objet ID3D11Device. La fonction renvoie également un objet ID3D11DeviceContext, mais cet objet n'est pas nécessaire pour cet exemple.

  2. Interrogez l'appareil Direct3D 11 pour connaître son interface DXGI.

  3. Créez un objet ID2D1Device en appelant la méthode ID2D1Factory::CreateDevice et en transmettant l'objet IDXGIDevice.

  4. Créez un pointeur ID2D1DeviceContext à l'aide de la méthode ID2D1Device::CreateDeviceContext.

Sélection d'une cible

Le code ci-dessous vous montre comment obtenir la texture Direct3D en 2 dimensions pour le tampon arrière de la fenêtre et comment créer une cible bitmap liée à cette texture vers laquelle le contexte de l'appareil Direct2D effectue le rendu.

        // 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());

Passons en revue les étapes de l'exemple de code précédent.

  1. Allouez une structure DXGI_SWAP_CHAIN_DESC1 et définissez les paramètres de la chaîne d'échange.

    Ces paramètres montrent un exemple de création d'une chaîne d'échange qu'une application du Windows Store peut utiliser.

  2. Obtenez l'adaptateur sur lequel l'appareil Direct3D et l'appareil DXGI sont exécutés et obtenez l'objet IDXGIFactory qui leur est associé. Vous devez utiliser cette fabrique DXGI pour vous assurer que la chaîne d'échange est créée sur le même adaptateur.

  3. Appelez la méthode IDXGIFactory2::CreateSwapChainForCoreWindow pour créer la chaîne d'échange. Utilisez la classe Windows::UI::CoreWindow pour la fenêtre principale d'une application Windows Store.

    Veillez à définir la latence maximale des trames sur 1 pour minimiser la consommation d'énergie.

    Si vous souhaitez effectuer le rendu d'un contenu Direct2D dans une application du Windows Store, consultez la méthode CreateSwapChainForComposition.

  4. Récupérez le tampon arrière de la chaîne d'échange. Le tampon arrière expose une interface ID3D11Texture2D allouée par la chaîne d'échange.

  5. Déclarez une structure D2D1_BITMAP_PROPERTIES1 et définissez les valeurs des propriétés. Définissez le format de pixel à BGRA car c'est le format utilisé par l'appareil Direct3D et l'appareil DXGI.

  6. Obtenez le tampon arrière sous la forme d'une IDXGISurface à transmettre à Direct2D. Direct2D n'accepte pas directement une ID3D11Texture2D.

    Créez un objet ID2D1Bitmap à partir du tampon arrière en utilisant la méthode ID2D1DeviceContext::CreateBitmapFromDxgiSurface.

  7. L'image bitmap Direct2D est maintenant liée au tampon arrière. Définissez la cible du contexte de l'appareil Direct2D sur l'image bitmap.

Comment effectuer le rendu et l'affichage

Maintenant que vous disposez d'une bitmap cible, vous pouvez y dessiner des primitives, des images, des effets d'image et du texte à l'aide du contexte d'appareil Direct2D. Le code ci-dessous vous montre comment dessiner un rectangle.

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);
);

Passons en revue les étapes de l'exemple de code précédent.

  1. Appelez la méthode CreateSolidColorBrush pour créer une brosse afin de peindre le rectangle.
  2. Appelez la méthode BeginDraw avant d'émettre des problèmes de dessin.
  3. Appelez la méthode DrawRectangle, le rectangle à dessiner et la brosse.
  4. Appelez la méthode EndDraw une fois que vous avez fini d'émettre des commandes de dessin.
  5. Affichez le résultat en appelant la méthode IDXGISwapChain::Present.

Vous pouvez désormais utiliser l'appareil Direct2D pour dessiner des primitives, des images, des effets d'image et du texte à l'écran.