Representación mediante un contexto de dispositivo Direct2D

En este tema aprenderás a crear contexto de dispositivoDirect2D en Windows 8. Esta información se aplica a ti si estás desarrollando aplicaciones de la Tienda Windows o una aplicación de escritorio mediante Direct2D. En este tema se describe el propósito de los objetos de contexto del dispositivo Direct2D, cómo crear ese objeto y una guía paso a paso sobre la representación y visualización de primitivas e imágenes de Direct2D. También obtendrá información sobre cómo cambiar los destinos de representación y agregar efectos a la aplicación.

¿Qué es un dispositivo Direct2D?

Necesita un dispositivo Direct2D y un dispositivo Direct3D para crear un contexto de dispositivo Direct2D. Un dispositivo Direct2D (expone un puntero de interfaz ID2D1Device ) representa un adaptador de pantalla. Un dispositivo Direct3D (expone un puntero de interfaz ID3D11Device ) está asociado a un dispositivo Direct2D. Cada aplicación debe tener un dispositivo Direct2D, pero puede tener más de un dispositivo.

¿Qué es un contexto de dispositivo Direct2D?

Un contexto de dispositivoDirect2D (expone un puntero de interfaz ID2D1DeviceContext) representa un conjunto de búferes de estado y comandos que se usan para representar en un destino. Puede llamar a métodos en el contexto del dispositivo para establecer el estado de canalización y generar comandos de representación mediante los recursos que pertenecen a un dispositivo.

Representación con Direct2D en Windows 8

En Windows 7 y versiones anteriores, usas un ID2D1HwndRenderTarget u otra interfaz de destino de representación para representar en una ventana o superficie. A partir de Windows 8, no se recomienda representar mediante métodos que se basan en interfaces como ID2D1HwndRenderTarget porque no funcionarán con aplicaciones de la Tienda Windows. Puedes usar un contexto de dispositivo para representarlo en un Hwnd si quieres hacer una aplicación de escritorio y seguir aprovechando las características adicionales del contexto del dispositivo . Sin embargo, el contexto del dispositivo es necesario para representar contenido en una aplicación de la Tienda Windows con Direct2D.

¿Por qué usar un contexto de dispositivo para representarlo?

Creación de un contexto de dispositivo Direct2D para la representación

El código aquí muestra cómo crear un dispositivo Direct3D11, obtener el dispositivo DXGI asociado, crear un dispositivo Direct2D y, finalmente, crear el contexto del dispositivo Direct2D para la representación.

Este es un diagrama de las llamadas al método y las interfaces que usa este código.

diagrama de dispositivos direct2d y direct3d y contextos de dispositivo.

Nota:

En este código se supone que ya tiene un objeto ID2D1Factory1 para obtener más información, consulte la página de referencia de 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 a recorrer los pasos del ejemplo de código anterior.

  1. Obtenga un puntero de interfaz ID3D11Device que necesitará para crear el contexto del dispositivo.

    • Declare las marcas de creación para configurar el dispositivo Direct3D para la compatibilidad con BGRA. Direct2D requiere el orden de color BGRA.

    • Declare una matriz de entradas de D3D_FEATURE_LEVEL que representen el conjunto de niveles de características que admitirá la aplicación.

      Nota

      Direct3D busca en la lista hasta que encuentre el nivel de característica admitido por el sistema host.

       

    • Use la función D3D11CreateDevice para crear un objeto ID3D11Device , la función también devolverá un objeto ID3D11DeviceContext , pero ese objeto no es necesario para este ejemplo.

  2. Consulta el dispositivo Direct3D 11 para su interfaz de dispositivo DXGI .

  3. Cree un objeto ID2D1Device llamando al método ID2D1Factory::CreateDevice y pasando el objeto IDXGIDevice .

  4. Cree un puntero ID2D1DeviceContext mediante el método ID2D1Device::CreateDeviceContext .

Selección de un destino

El código aquí muestra cómo obtener la textura 2 dimensional de Direct3D para el búfer de reserva de ventanas y crear un destino de mapa de bits que se vincula a esta textura a la que se representa el contexto del 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());

Vamos a recorrer los pasos del ejemplo de código anterior.

  1. Asigne una estructura DXGI_SWAP_CHAIN_DESC1 y defina la configuración de la cadena de intercambio.

    Esta configuración muestra un ejemplo de cómo crear una cadena de intercambio que una aplicación de la Tienda Windows puede usar.

  2. Obtenga el adaptador en el que se ejecutan el dispositivo Direct3D y el dispositivo DXGI y obtenga el objeto IDXGIFactory asociado a ellos. Debe usar esta fábrica DXGI para asegurarse de que la cadena de intercambio se crea en el mismo adaptador.

  3. Llame al método IDXGIFactory2::CreateSwapChainForCoreWindow para crear la cadena de intercambio. Usa la clase Windows::UI::CoreWindow para la ventana principal de una aplicación de la Tienda Windows.

    Asegúrese de establecer la latencia máxima de fotogramas en 1 para minimizar el consumo de energía.

    Si quieres representar contenido de Direct2D en una aplicación de la Tienda Windows, consulta el método CreateSwapChainForComposition .

  4. Obtenga el búfer de reserva de la cadena de intercambio. El búfer de reserva expone una interfaz ID3D11Texture2D asignada por la cadena de intercambio.

  5. Declare una estructura D2D1_BITMAP_PROPERTIES1 y establezca los valores de propiedad. Establezca el formato de píxel en BGRA porque es el formato del dispositivo Direct3D y el uso del dispositivo DXGI .

  6. Obtenga el búfer de reserva como IDXGISurface para pasar a Direct2D. Direct2D no acepta un ID3D11Texture2D directamente.

    Cree un objeto ID2D1Bitmap desde el búfer de reserva mediante el método ID2D1DeviceContext::CreateBitmapFromDxgiSurface .

  7. Ahora el mapa de bits de Direct2D está vinculado al búfer de reserva. Establezca el destino en el contexto del dispositivo Direct2D en el mapa de bits.

Cómo representar y mostrar

Ahora que tiene un mapa de bits de destino, puede dibujar primitivos, imágenes, efectos de imagen y texto en él mediante el contexto del dispositivo Direct2D. El código aquí muestra cómo dibujar un rectá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 a recorrer los pasos del ejemplo de código anterior.

  1. Llame a CreateSolidColorBrush para crear un pincel para pintar el rectángulo.
  2. Llame al método BeginDraw antes de emitir cualquier comando de dibujo.
  3. Llame al método DrawRectangle el rectángulo que se va a dibujar y el pincel.
  4. Llame al método EndDraw una vez que haya terminado de emitir comandos de dibujo.
  5. Muestre el resultado llamando al método IDXGISwapChain::P resent .

Ahora puedes usar el contexto del dispositivo Direct2D dibujando primitivos, imágenes, efectos de imagen y texto en la pantalla.