Freigeben über


Übersicht über die Interoperabilität von Direct2D und Direct3D

Hardware-beschleunigte 2D- und 3D-Grafiken werden immer häufiger in Anwendungen eingesetzt, die keine Spiele sind, und die meisten Spieleanwendungen verwenden 2D-Grafiken in Form von Menüs und Heads-Up-Displays (HUDs). Die effiziente Kombination von herkömmlichem 2D-Rendering und Direct3D-Rendering kann einen großen Mehrwert bieten.

Dieses Thema beschreibt, wie Sie 2D- und 3D-Grafiken mithilfe von Direct2D und Direct3Dintegrieren können.

Voraussetzungen

Diese Übersicht setzt voraus, dass Sie mit den grundlegenden Direct2D-Zeichenoperationen vertraut sind. Eine Anleitung dazu finden Sie unter Erstellen einer einfachen Direct2D-Anwendung. Es wird außerdem vorausgesetzt, dass Sie mit Direct3D 10.1programmieren können.

Unterstützte Direct3D-Versionen

Mit DirectX 11.0 unterstützt Direct2D nur die Interoperabilität mit Direct3D 10.1 Geräten. Mit DirectX 11.1 oder höher unterstützt Direct2D auch die Interoperabilität mit Direct3D 11.

Interoperabilität durch DXGI

Ab Direct3D 10 verwendet die Direct3D-Runtime-Umgebung DXGI für die Ressourcenverwaltung. Die DXGI-Runtime-Schicht ermöglicht die prozessübergreifende gemeinsame Nutzung von Videospeicheroberflächen und dient als Grundlage für andere videospeicherbasierte Runtime-Plattformen. Direct2D verwendet DXGI, um mit Direct3D zu interagieren.

Es gibt zwei primäre Möglichkeiten, Direct2D und Direct3D zusammen zu verwenden:

  • Sie können Direct2D-Inhalte in eine Direct3D-Oberfläche schreiben, indem Sie ein IDXGISurface erhalten und es mit der CreateDxgiSurfaceRenderTarget verwenden, um ein ID2D1RenderTargetzu erstellen. Sie können dann das Rendering-Ziel verwenden, um dreidimensionalen Grafiken eine zweidimensionale Oberfläche oder einen Hintergrund hinzuzufügen oder eine Direct2D-Zeichnung als Textur für ein dreidimensionales Objekt zu verwenden.
  • Indem Sie CreateSharedBitmap verwenden, um eine ID2D1Bitmap aus einer IDXGISurfacezu erstellen, können Sie eine Direct3D-Szene in eine Bitmap schreiben und sie mit Direct2D rendern.

Schreiben auf eine Direct3D-Oberfläche mit einem DXGI-Oberflächen-Rendering-Ziel

Um in eine Direct3D-Oberfläche zu schreiben, erhalten Sie ein IDXGISurface und übergeben es an die Methode CreateDxgiSurfaceRenderTarget , um ein DXGI-Oberflächen-Rendertarget zu erstellen. Sie können dann das DXGI-Oberflächen-Rendering-Ziel verwenden, um 2-D-Inhalte auf die DXGI-Oberfläche zu zeichnen.

Ein DXGI-Oberflächen-Rendertarget ist eine Art ID2D1RenderTarget. Wie andere Direct2D-Renderziele können Sie damit Ressourcen erstellen und Zeichenbefehle erteilen.

Das Rendering-Ziel der DXGI-Oberfläche und die DXGI-Oberfläche müssen das gleiche DXGI-Format verwenden. Wenn Sie bei der Erstellung des Renderziels das Format DXGI_FORMAT_UNKOWN angeben, wird automatisch das Format der Oberfläche verwendet.

Das DXGI-Surface-Rendering-Ziel führt keine DXGI-Surface-Synchronisierung durch.

Erstellen einer DXGI-Oberfläche

Mit Direct3D 10 gibt es mehrere Möglichkeiten, eine DXGI-Oberfläche zu erhalten. Sie können eine IDXGISwapChain für ein Gerät erstellen und dann die Methode GetBuffer der Swap Chain verwenden, um eine DXGI-Oberfläche zu erhalten. Sie können auch ein Gerät verwenden, um eine Textur zu erstellen, und diese Textur dann als DXGI-Oberfläche verwenden.

Unabhängig davon, wie Sie die DXGI-Oberfläche erstellen, muss die Oberfläche eines der DXGI-Formate verwenden, die von DXGI-Oberflächen-Rendertargets unterstützt werden. Eine Liste finden Sie unter Unterstützte Pixelformate und Alpha-Modi.

Außerdem muss das ID3D10Device1 , das mit der DXGI-Oberfläche verbunden ist, BGRA DXGI-Formate unterstützen, damit die Oberfläche mit Direct2D funktioniert. Um diese Unterstützung sicherzustellen, verwenden Sie das D3D10_CREATE_DEVICE_BGRA_SUPPORT-Flag, wenn Sie die Methode D3D10CreateDevice1 aufrufen, um das Gerät zu erstellen.

Der folgende Code definiert eine Methode, die ein ID3D10Device1erstellt. Es wählt die beste verfügbare Funktionsstufe aus und greift auf Windows Advanced Rasterization Platform (WARP) zurück, wenn kein Hardware-Rendering verfügbar ist.

HRESULT DXGISampleApp::CreateD3DDevice(
    IDXGIAdapter *pAdapter,
    D3D10_DRIVER_TYPE driverType,
    UINT flags,
    ID3D10Device1 **ppDevice
    )
{
    HRESULT hr = S_OK;

    static const D3D10_FEATURE_LEVEL1 levelAttempts[] =
    {
        D3D10_FEATURE_LEVEL_10_0,
        D3D10_FEATURE_LEVEL_9_3,
        D3D10_FEATURE_LEVEL_9_2,
        D3D10_FEATURE_LEVEL_9_1,
    };

    for (UINT level = 0; level < ARRAYSIZE(levelAttempts); level++)
    {
        ID3D10Device1 *pDevice = NULL;
        hr = D3D10CreateDevice1(
            pAdapter,
            driverType,
            NULL,
            flags,
            levelAttempts[level],
            D3D10_1_SDK_VERSION,
            &pDevice
            );

        if (SUCCEEDED(hr))
        {
            // transfer reference
            *ppDevice = pDevice;
            pDevice = NULL;
            break;
        }
    }

    return hr;
}

Das nächste Codebeispiel verwendet die Methode CreateD3DDevice aus dem vorherigen Beispiel, um ein Direct3D-Gerät zu erstellen, das DXGI-Oberflächen für die Verwendung mit Direct2D erzeugen kann.

// Create device
hr = CreateD3DDevice(
    NULL,
    D3D10_DRIVER_TYPE_HARDWARE,
    nDeviceFlags,
    &pDevice
    );

if (FAILED(hr))
{
    hr = CreateD3DDevice(
        NULL,
        D3D10_DRIVER_TYPE_WARP,
        nDeviceFlags,
        &pDevice
        );
}

Direct2D-Inhalt in einen Swap-Chain-Puffer schreiben

Der einfachste Weg, einer Direct3D-Szene Direct2D-Inhalte hinzuzufügen, ist die Verwendung der Methode GetBuffer einer IDXGISwapChain , um eine DXGI-Oberfläche zu erhalten, Verwenden Sie dann die Oberfläche mit der Methode CreateDxgiSurfaceRenderTarget , um ein ID2D1RenderTarget zu erstellen, mit dem Sie Ihren 2D-Inhalt zeichnen.

Bei diesem Ansatz werden Ihre Inhalte nicht dreidimensional wiedergegeben; sie haben weder Perspektive noch Tiefe. Sie ist jedoch für mehrere gängige Aufgaben nützlich:

  • Erstellen eines 2-D-Hintergrunds für eine 3-D-Szene.
  • Erstellen einer 2-D-Oberfläche vor einer 3-D-Szene.
  • Verwendung von Direct3D-Multisampling beim Rendern von Direct2D-Inhalten.

Der nächste Abschnitt zeigt, wie Sie einen 2-D-Hintergrund für eine 3-D-Szene erstellen.

Beispiel: Zeichnen Sie einen 2-D-Hintergrund

Die folgenden Schritte beschreiben, wie Sie ein DXGI-Oberflächen-Rendering-Ziel erstellen und es verwenden, um einen Hintergrund mit Farbverlauf zu zeichnen.

  1. Verwenden Sie die Methode CreateSwapChain , um eine Swap-Kette für ein ID3D10Device1 (die Variable m_pDevice ) zu erstellen. Die Swap-Kette verwendet das DXGI_FORMAT_B8G8R8A8_UNORM-DXGI-Format, eines der von Direct2D unterstützten DXGI-Formate.

    if (SUCCEEDED(hr))
    {
        hr = pDevice->QueryInterface(&m_pDevice);
    }
    if (SUCCEEDED(hr))
    {
        hr = pDevice->QueryInterface(&pDXGIDevice);
    }
    if (SUCCEEDED(hr))
    {
        hr = pDXGIDevice->GetAdapter(&pAdapter);
    }
    if (SUCCEEDED(hr))
    {
        hr = pAdapter->GetParent(IID_PPV_ARGS(&pDXGIFactory));
    }
    if (SUCCEEDED(hr))
    {
        DXGI_SWAP_CHAIN_DESC swapDesc;
        ::ZeroMemory(&swapDesc, sizeof(swapDesc));
    
        swapDesc.BufferDesc.Width = nWidth;
        swapDesc.BufferDesc.Height = nHeight;
        swapDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
        swapDesc.BufferDesc.RefreshRate.Numerator = 60;
        swapDesc.BufferDesc.RefreshRate.Denominator = 1;
        swapDesc.SampleDesc.Count = 1;
        swapDesc.SampleDesc.Quality = 0;
        swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
        swapDesc.BufferCount = 1;
        swapDesc.OutputWindow = m_hwnd;
        swapDesc.Windowed = TRUE;
    
        hr = pDXGIFactory->CreateSwapChain(m_pDevice, &swapDesc, &m_pSwapChain);
    }
    
  2. Verwenden Sie die Methode GetBuffer der Swap-Kette, um eine DXGI-Oberfläche zu erhalten.

    // Get a surface in the swap chain
    hr = m_pSwapChain->GetBuffer(
        0,
        IID_PPV_ARGS(&pBackBuffer)
        );
    
  3. Verwenden Sie die DXGI-Oberfläche, um ein DXGI-Rendering-Ziel zu erstellen.

    // Initialize *hwnd* with the handle of the window displaying the rendered content.
    HWND hwnd;
    
    // Create the DXGI Surface Render Target.
    float dpi = GetDpiForWindow(hwnd);
    
    D2D1_RENDER_TARGET_PROPERTIES props =
        D2D1::RenderTargetProperties(
            D2D1_RENDER_TARGET_TYPE_DEFAULT,
            D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED),
            dpiX,
            dpiY);
    
    // Create a Direct2D render target that can draw into the surface in the swap chain
    
    hr = m_pD2DFactory->CreateDxgiSurfaceRenderTarget(
        pBackBuffer,
        &props,
        &m_pBackBufferRT);
    
  4. Verwenden Sie das Renderziel, um einen Hintergrund mit Farbverlauf zu zeichnen.

    // Swap chain will tell us how big the back buffer is
    DXGI_SWAP_CHAIN_DESC swapDesc;
    hr = m_pSwapChain->GetDesc(&swapDesc);
    
    if (SUCCEEDED(hr))
    {
        // Draw a gradient background.
        if (m_pBackBufferRT)
        {
            D2D1_SIZE_F targetSize = m_pBackBufferRT->GetSize();
    
            m_pBackBufferRT->BeginDraw();
    
            m_pBackBufferGradientBrush->SetTransform(
                D2D1::Matrix3x2F::Scale(targetSize)
                );
    
            D2D1_RECT_F rect = D2D1::RectF(
                0.0f,
                0.0f,
                targetSize.width,
                targetSize.height
                );
    
            m_pBackBufferRT->FillRectangle(&rect, m_pBackBufferGradientBrush);
    
            hr = m_pBackBufferRT->EndDraw();
        }
    ...
    

Der Code wird in diesem Beispiel weggelassen.

Direct2D-Inhalt als Textur verwenden

Eine andere Möglichkeit, Direct2D-Inhalte mit Direct3D zu verwenden, besteht darin, mit Direct2D eine 2-D-Textur zu erzeugen und diese Textur dann auf ein 3-D-Modell anzuwenden. Dazu erstellen Sie eine ID3D10Texture2D, erhalten eine DXGI-Oberfläche aus der Textur und verwenden dann die Oberfläche, um ein DXGI-Oberflächen-Renderingziel zu erstellen. Die ID3D10Texture2D Oberfläche muss das D3D10_BIND_RENDER_TARGET Bindungsflag verwenden und ein DXGI-Format nutzen, das von DXGI-Oberflächen-Rendertargets unterstützt wird. Eine Liste der unterstützten DXGI-Formate finden Sie unter Unterstützte Pixelformate und Alpha-Modi.

Beispiel: Direct2D-Inhalt als Textur verwenden

Die folgenden Beispiele zeigen, wie Sie ein DXGI-Oberflächen-Rendering-Ziel erstellen, das in eine 2-D-Textur rendert (dargestellt durch eine ID3D10Texture2D).

  1. Verwenden Sie zunächst ein Direct3D-Gerät, um eine 2-D-Textur zu erstellen. Die Textur verwendet die D3D10_BIND_RENDER_TARGET- und D3D10_BIND_SHADER_RESOURCE-Bind-Flags, und es verwendet das DXGI_FORMAT_B8G8R8A8_UNORM DXGI-Format, eines der von Direct2D unterstützten DXGI-Formate.

    // Allocate an offscreen D3D surface for D2D to render our 2D content into
    D3D10_TEXTURE2D_DESC texDesc;
    texDesc.ArraySize = 1;
    texDesc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
    texDesc.CPUAccessFlags = 0;
    texDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
    texDesc.Height = 512;
    texDesc.Width = 512;
    texDesc.MipLevels = 1;
    texDesc.MiscFlags = 0;
    texDesc.SampleDesc.Count = 1;
    texDesc.SampleDesc.Quality = 0;
    texDesc.Usage = D3D10_USAGE_DEFAULT;
    
    hr = m_pDevice->CreateTexture2D(&texDesc, NULL, &m_pOffscreenTexture);
    
  2. Verwenden Sie die Textur, um eine DXGI-Oberfläche zu erhalten.

    IDXGISurface *pDxgiSurface = NULL;
    
    hr = m_pOffscreenTexture->QueryInterface(&pDxgiSurface);
    
  3. Verwenden Sie die Oberfläche mit der Methode CreateDxgiSurfaceRenderTarget , um ein Direct2D-Rendering-Ziel zu erhalten.

    if (SUCCEEDED(hr))
    {
        // Create a D2D render target that can draw into our offscreen D3D
        // surface. Given that we use a constant size for the texture, we
        // fix the DPI at 96.
        D2D1_RENDER_TARGET_PROPERTIES props =
            D2D1::RenderTargetProperties(
                D2D1_RENDER_TARGET_TYPE_DEFAULT,
                D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED),
                96,
                96);
    
        hr = m_pD2DFactory->CreateDxgiSurfaceRenderTarget(
                pDxgiSurface,
                &props,
                &m_pRenderTarget);
    }
    

Nachdem Sie nun ein Direct2D-Rendering-Ziel erhalten und es mit einer Direct3D-Textur verknüpft haben, können Sie das Rendering-Ziel verwenden, um Direct2D-Inhalte auf diese Textur zu zeichnen, und Sie können diese Textur auf Direct3D-Primitive anwenden.

Der Code wird in diesem Beispiel weggelassen.

Größenänderung eines DXGI-Oberflächenrenderziels

DXGI-Oberflächen-Renderziele unterstützen die Methode ID2D1RenderTarget::Resize nicht. Um die Größe eines DXGI-Oberflächen-Renderziels zu ändern, muss die Anwendung es freigeben und neu erstellen.

Dieser Vorgang kann möglicherweise zu Leistungsproblemen führen. Das Rendering-Ziel ist möglicherweise die letzte aktive Direct2D-Ressource, die einen Verweis auf das ID3D10Device1 enthält, das mit der DXGI-Oberfläche des Rendering-Ziels verbunden ist. Wenn die Anwendung das Rendering-Ziel freigibt und die Referenz ID3D10Device1 zerstört wird, muss eine neue erstellt werden.

Sie können diesen potenziell kostspieligen Vorgang vermeiden, indem Sie mindestens eine Direct2D-Ressource, die vom Rendering-Ziel erstellt wurde, behalten, während Sie das Rendering-Ziel neu erstellen. Im Folgenden finden Sie einige Direct2D-Ressourcen, die für diesen Ansatz geeignet sind:

Um diesem Ansatz gerecht zu werden, sollte Ihre Größenänderungsmethode prüfen, ob das Direct3D-Gerät verfügbar ist. Wenn es verfügbar ist, geben Sie Ihre DXGI-Oberflächen-Renderziele frei und erstellen sie neu, behalten aber alle zuvor erstellten Ressourcen und verwenden sie wieder. Dies funktioniert, weil, wie im Überblick über die Ressourcenbeschrieben, die von zwei Rendering-Zielen erstellten Ressourcen kompatibel sind, wenn beide Rendering-Ziele mit demselben Direct3D-Gerät verbunden sind.

Unterstützte Pixelformate und Alpha-Modi

CreateDxgiSurfaceRenderTarget

Windows DirectX Graphics