Rendering mit Hilfe eines Direct2D-Gerätekontextes

In diesem Thema erfahren Sie, wie Sie einen Direct2D-Gerätekontext in Windows 8 erstellen. Diese Informationen gelten für Sie, wenn Sie Windows Store-Apps oder eine Desktop-App unter Verwendung von Direct2D entwickeln. Dieses Thema beschreibt den Zweck von Direct2D-Gerätekontextobjekten, wie Sie dieses Objekt erstellen und eine schrittweise Anleitung zum Rendern und Anzeigen von Direct2D-Primitiven und -Bildern. Sie werden auch lernen, wie Sie Renderziele wechseln und Ihrer App Effekte hinzufügen.

Was ist ein Direct2D-Gerät?

Sie benötigen ein Direct2D-Gerät und ein Direct3D-Gerät, um einen Direct2D-Gerätekontext zu erstellen. Ein Direct2D-Gerät (stellt einen ID2D1Device Schnittstellenzeiger zur Verfügung) stellt einen Bildschirm-Adapter dar. Ein Direct3D-Gerät (zeigt einen ID3D11Device-Schnittstellenzeiger an) ist mit einem Direct2D-Gerät verbunden. Jede App muss ein Direct2D-Gerät haben, kann aber mehr als ein Gerät haben.

Was ist ein Direct2D-Gerätekontext?

Ein Direct2D-Gerätekontext (stellt einen ID2D1DeviceContext-Schnittstellenzeiger zur Verfügung) stellt einen Satz von Status- und Befehlspuffern dar, die Sie zum Rendern auf ein Ziel verwenden. Sie können Methoden auf dem Gerätekontext aufrufen, um den Status der Pipeline festzulegen und Rendering-Befehle zu erstellen, indem Sie die Ressourcen verwenden, die einem Gerät gehören.

Rendering mit Direct2D unter Windows 8

Unter Windows 7 und früher verwenden Sie ein ID2D1HwndRenderTarget oder eine andere Renderziel-Schnittstelle, um auf ein Fenster oder eine Oberfläche zu rendern. Ab Windows 8 raten wir davon ab, Methoden zu verwenden, die auf Schnittstellen wie ID2D1HwndRenderTarget beruhen, da sie mit Windows Store-Apps nicht funktionieren. Sie können einen Gerätekontext zum Rendern in ein Hwnd verwenden, wenn Sie eine Desktop-App erstellen und trotzdem die zusätzlichen Funktionen des Gerätekontexts nutzen möchten. Der Gerätekontext ist jedoch erforderlich, um Inhalte in Windows Store-Apps mit Direct2D zu rendern.

Warum einen Gerätekontext zum Rendern verwenden?

  • Sie können für Windows Store-Apps rendern.
  • Sie können das Renderziel jederzeit vor, während und nach dem Rendering ändern. Der Gerätekontext stellt sicher, dass die Aufrufe von Zeichenmethoden in der richtigen Reihenfolge ausgeführt werden, und wendet sie an, wenn Sie das Renderziel wechseln.
  • Sie können mehr als einen Fenstertyp mit einem Gerätekontext verwenden. Sie können einen Gerätekontext und eine DXGI-Swap-Chain verwenden, um direkt auf ein Windows::UI::Core::CoreWindow oder ein Windows::UI::XAML::SwapChainBackgroundPanel zu rendern.
  • Sie können den Direct2D-Gerätekontext verwenden, um Direct2D-Effekte zu erstellen und die Ausgabe eines Bild-Effekts oder eines Effekt-Graphen auf ein Renderziel zu rendern.
  • Sie können mehrere Gerätekontexte haben, was für die Verbesserung der Leistung in einer App mit mehreren Threads hilfreich sein kann. Weitere Informationen finden Sie unter Multithreaded Direct2D-Apps.
  • Der Gerätekontext arbeitet eng mit Direct3D zusammen und bietet Ihnen mehr Zugriff auf Direct3D-Optionen.

So erstellen Sie einen Direct2D-Gerätekontext für das Rendering

Der Code hier zeigt Ihnen, wie Sie ein Direct3D11-Gerät erstellen, das zugehörige DXGI-Gerät abrufen, ein Direct2D-Gerät erstellen und schließlich den Direct2D-Gerätekontext für das Rendering erstellen.

Hier sehen Sie ein Diagramm der Methodenaufrufe und der Schnittstellen, die dieser Code verwendet.

Diagramm der Direct2D- und Direct3D-Geräte und -Gerätekontexte.

Hinweis

Dieser Code setzt voraus, dass Sie bereits ein ID2D1Factory1-Objekt besitzen. Weitere Informationen finden Sie auf der ID2D1Factory-Referenzseite.

 

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

Gehen wir die Schritte im vorangehenden Code-Beispiel durch.

  1. Holen Sie sich einen ID3D11Device-Schnittstellenzeiger, den Sie benötigen, um den Gerätekontext zu erstellen.

    • Deklarieren Sie die Erstellungs-Flags, um das Direct3D-Gerät für die BGRA-Unterstützung festzulegen. Direct2D erfordert die BGRA-Farbreihenfolge.

    • Deklarieren Sie ein Array von D3D_FEATURE_LEVEL-Einträgen, die den Satz von Funktionsebenen repräsentieren, die Ihre App unterstützen wird.

      Hinweis

      Direct3D durchsucht Ihre Liste, bis es die vom Host-System unterstützte Funktionsebene findet.

       

    • Verwenden Sie die Funktion D3D11CreateDevice, um ein ID3D11Device-Objekt zu erstellen. Die Funktion gibt auch ein ID3D11DeviceContext-Objekt zurück, aber dieses Objekt wird für dieses Beispiel nicht benötigt.

  2. Fragen Sie das Direct3D 11-Gerät nach seiner DXGI Device-Schnittstelle ab.

  3. Erstellen Sie ein ID2D1Device-Objekt, indem Sie die ID2D1Factory::CreateDevice-Methode aufrufen und das IDXGIDevice-Objekt übergeben.

  4. Erstellen Sie einen ID2D1DeviceContext-Zeiger mit der Methode ID2D1Device::CreateDeviceContext.

Auswählen eines Ziels

Der Code hier zeigt Ihnen, wie Sie die zweidimensionale Direct3D-Textur für den Fenster-Hintergrundpuffer abrufen und ein Bitmap-Ziel erstellen, das auf diese Textur verlinkt, auf die der Direct2D-Gerätekontext rendert.

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

Lassen Sie uns die Schritte des vorangegangenen Code-Beispiels durchgehen.

  1. Weisen Sie eine DXGI_SWAP_CHAIN_DESC1-Struktur zu, und legen Sie die Einstellungen für die Swap-Chain fest.

    Diese Einstellungen zeigen ein Beispiel dafür, wie Sie eine Swap-Chain erstellen, die eine Windows Store-App verwenden kann.

  2. Holen Sie sich den Adapter, auf dem das Direct3D-Gerät und das DXGI-Gerät ausgeführt werden, und holen Sie sich das IDXGIFactory-Objekt, das mit ihnen verbunden ist. Sie müssen diese DXGI-Factory verwenden, damit die Swap-Chain auf demselben Adapter erstellt wird.

  3. Rufen Sie die Methode IDXGIFactory2::CreateSwapChainForCoreWindow auf, um die Swap-Chain zu erstellen. Verwenden Sie die Klasse Windows::UI::CoreWindow für das Hauptfenster einer Windows Store-App.

    Stellen Sie sicher, dass Sie die maximale Frame-Latenz auf 1 festlegen, um den Stromverbrauch zu minimieren.

    Wenn Sie Direct2D-Inhalte in einer Windows Store-App rendern möchten, sehen Sie sich die Methode CreateSwapChainForComposition an.

  4. Holen Sie den Backbuffer aus der Swap-Chain. Der Backbuffer stellt eine ID3D11Texture2D-Schnittstelle zur Verfügung, die von der Swap-Chain zugewiesen wird.

  5. Deklarieren Sie eine D2D1_BITMAP_PROPERTIES1-Struktur, und legen Sie die Eigenschaftswerte fest. Legen Sie das Pixelformat auf BGRA fest, da dies das Format ist, das das Direct3D-Gerät und das DXGI-Gerät verwenden.

  6. Holen Sie den Backbuffer als IDXGISurface, um ihn an Direct2D zu übergeben. Direct2D akzeptiert eine ID3D11Texture2D nicht direkt.

    Erstellen Sie mit der Methode ID2D1DeviceContext::CreateBitmapFromDxgiSurface ein ID2D1Bitmap-Objekt aus dem Backbuffer.

  7. Jetzt wird die Direct2D-Bitmap mit dem Backbuffer gelinkt. Legen Sie das Ziel auf dem Direct2D-Gerätekontext auf die Bitmap fest.

Rendern und Anzeigen

Jetzt, da Sie eine Ziel-Bitmap haben, können Sie mit dem Direct2D-Gerätekontext Primitiven, Bilder, Bildeffekte und Text darauf zeichnen. Der folgende Code zeigt Ihnen, wie Sie ein Rechteck zeichnen können.

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

Lassen Sie uns die Schritte des vorangegangenen Code-Beispiels durchgehen.

  1. Rufen Sie die Methode CreateSolidColorBrush auf, um einen Brush zum Zeichnen des Rechtecks zu erstellen.
  2. Rufen Sie die Methode BeginDraw auf, bevor Sie einen Zeichenbefehl erteilen.
  3. Zeichnen Sie mit der Methode DrawRectangle das Rechteck mit dem Brush.
  4. Rufen Sie die Methode EndDraw auf, nachdem Sie die Zeichenbefehle abgeschlossen haben.
  5. Zeigen Sie das Ergebnis an, indem Sie die Methode IDXGISwapChain::Present aufrufen.

Jetzt können Sie mit dem Direct2D-Gerätekontext Primitive, Bilder, Bildeffekte und Text auf die Seite zeichnen.