Come eseguire il rendering usando un contesto di dispositivo Direct2D

In questo argomento si apprenderà come creare il contesto di dispositivo Direct2D in Windows 8. Queste informazioni si applicano all'utente se si sviluppano app di Windows Store o un'app desktop tramite Direct2D. Questo argomento descrive lo scopo degli oggetti contesto di dispositivo Direct2D, come creare tale oggetto e una guida dettagliata sul rendering e sulla visualizzazione di primitive e immagini Direct2D. Si apprenderà anche come cambiare le destinazioni di rendering e aggiungere effetti all'app.

Che cos'è un dispositivo Direct2D?

È necessario un dispositivo Direct2D e un dispositivo Direct3D per creare un contesto di dispositivo Direct2D. Un dispositivo Direct2D (espone un puntatore all'interfaccia ID2D1Device ) rappresenta una scheda di visualizzazione. Un dispositivo Direct3D (espone un puntatore all'interfaccia ID3D11Device ) è associato a un dispositivo Direct2D. Ogni app deve avere un dispositivo Direct2D, ma può avere più di un dispositivo.

Che cos'è un contesto di dispositivo Direct2D?

Un contesto di dispositivo Direct2D (espone un puntatore all'interfaccia ID2D1DeviceContext) rappresenta un set di buffer di stato e comandi usati per eseguire il rendering in una destinazione. È possibile chiamare i metodi nel contesto di dispositivo per impostare lo stato della pipeline e generare comandi di rendering usando le risorse di proprietà di un dispositivo.

Rendering con Direct2D in Windows 8

In Windows 7 e versioni precedenti si usa un ID2D1HwndRenderTarget o un'altra interfaccia di destinazione di rendering per eseguire il rendering in una finestra o in una superficie. A partire da Windows 8, non è consigliabile eseguire il rendering usando metodi che si basano su interfacce come ID2D1HwndRenderTarget perché non funzioneranno con le app di Windows Store. Puoi usare un contesto di dispositivo per eseguire il rendering in un oggetto Hwnd se vuoi creare un'app desktop e sfruttare comunque le funzionalità aggiuntive del contesto di dispositivo. Tuttavia, il contesto del dispositivo è necessario per eseguire il rendering del contenuto in un'app di Windows Store con Direct2D.

Perché usare un contesto di dispositivo per eseguire il rendering?

  • È possibile eseguire il rendering per le app di Windows Store.
  • È possibile modificare la destinazione di rendering in qualsiasi momento prima, durante e dopo il rendering. Il contesto del dispositivo garantisce che le chiamate ai metodi di disegno vengano eseguite in ordine e le applichi quando si cambia la destinazione di rendering.
  • È possibile usare più di un tipo di finestra con un contesto di dispositivo. Puoi usare un contesto di dispositivo e una catena di scambio DXGI per eseguire il rendering direttamente in Windows::UI::Core::CoreWindow o Windows::UI::XAML::SwapChainBackgroundPanel.
  • È possibile usare il contesto di dispositivo Direct2D per creare effetti Direct2D e per eseguire il rendering dell'output di un effetto o di un grafico effetto su una destinazione di rendering.
  • È possibile avere più contesti di dispositivo, che possono essere utili per migliorare le prestazioni in un'app a thread. Per altre informazioni, vedere App Direct2D multithreading.
  • Il contesto di dispositivo interagisce strettamente con Direct3D, offrendoti più accesso alle opzioni Direct3D.

Come creare un contesto di dispositivo Direct2D per il rendering

Il codice seguente illustra come creare un dispositivo Direct3D11, ottenere il dispositivo DXGI associato, creare un dispositivo Direct2D e infine creare il contesto di dispositivo Direct2D per il rendering.

Di seguito è riportato un diagramma delle chiamate al metodo e delle interfacce usate da questo codice.

diagramma dei dispositivi direct2d e direct3d e dei contesti di dispositivo.

Nota

Questo codice presuppone che tu abbia già un oggetto ID2D1Factory1. Per altre informazioni, vedi la pagina di riferimento 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
            )
        );

Verranno ora illustrati i passaggi dell'esempio di codice precedente.

  1. Ottenere un puntatore all'interfaccia ID3D11Device necessario per creare il contesto di dispositivo.

  2. Eseguire una query sul dispositivo Direct3D 11 per l'interfaccia del dispositivo DXGI.

  3. Creare un oggetto ID2D1Device chiamando il metodo ID2D1Factory::CreateDevice e passando l'oggetto IDXGIDevice.

  4. Creare un puntatore ID2D1DeviceContext usando il metodo ID2D1Device::CreateDeviceContext.

Selezione di una destinazione

Il codice seguente illustra come ottenere la trama Direct3D 2 dimensionale per il buffer nascosto della finestra e creare una destinazione bitmap che collega a questa trama a cui viene eseguito il rendering del contesto di dispositivo Direct2D.

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

Verranno ora illustrati i passaggi dell'esempio di codice precedente.

  1. Allocare una struttura DXGI_SWAP_CHAIN_DESC1 e definire le impostazioni per la catena di scambio.

    Queste impostazioni mostrano un esempio di come creare una catena di scambio che un'app di Windows Store può usare.

  2. Ottenere l'adattatore su cui sono in esecuzione il dispositivo Direct3D e il dispositivo DXGI e ottenere l'oggetto IDXGIFactory associato. È necessario usare questa factory DXGI per assicurarsi che la catena di scambio venga creata sullo stesso adattatore.

  3. Chiamare il metodo IDXGIFactory2::CreateSwapChainForCoreWindow per creare la catena di scambio. Usa la classe Windows::UI::CoreWindow per la finestra principale di un'app di Windows Store.

    Assicurarsi di impostare la latenza massima dei fotogrammi su 1 per ridurre al minimo il consumo di energia.

    Se vuoi eseguire il rendering del contenuto Direct2D in un'app di Windows Store, vedi il metodo CreateSwapChainForComposition.

  4. Recuperare il buffer nascosto dalla catena di scambio. Il buffer nascosto espone un'interfaccia ID3D11Texture2D allocata dalla catena di scambio

  5. Dichiarare uno struct D2D1_BITMAP_PROPERTIES1 e impostare i valori della proprietà. Impostare il formato pixel su BGRA perché si tratta del formato del dispositivo Direct3D e dell'uso del dispositivo DXGI.

  6. Ottenere il buffer nascosto come IDXGISurface da passare a Direct2D. Direct2D non accetta direttamente un ID3D11Texture2D.

    Creare un oggetto ID2D1Bitmap dal buffer nascosto usando il metodo ID2D1DeviceContext::CreateBitmapFromDxgiSurface.

  7. Ora la bitmap Direct2D è collegata al buffer nascosto. Impostare la destinazione nel contesto di dispositivo Direct2D sulla bitmap.

Come eseguire il rendering e la visualizzazione

Ora che hai una bitmap di destinazione, puoi disegnare primitive, immagini, effetti immagine e testo usando il contesto di dispositivo Direct2D. Il codice seguente illustra come disegnare un rettangolo.

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

Verranno ora illustrati i passaggi dell'esempio di codice precedente.

  1. Chiamare CreateSolidColorBrush per creare un pennello per disegnare il rettangolo.
  2. Chiamare il metodo BeginDraw prima di eseguire qualsiasi comando di disegno.
  3. Chiamare il metodo DrawRectangle il rettangolo da disegnare e il pennello.
  4. Chiamare il metodo EndDraw dopo aver completato l'emissione di comandi di disegno.
  5. Visualizzare il risultato chiamando il metodo IDXGISwapChain::P resent.

È ora possibile usare il contesto di dispositivo Direct2D disegnare primitive, immagini, effetti immagine e testo sullo schermo.