Как отобразить с помощью контекста устройства Direct2D

В этом разделе вы узнаете о создании контекста устройства Direct2D в Windows 8. Эта информация применяется к вам, если вы разрабатываете приложения Магазина Windows или классическое приложение с помощью Direct2D. В этом разделе описывается назначение объектов контекста устройства Direct2D, создание этого объекта и пошаговое руководство по отрисовке и отображению примитивов и изображений Direct2D. Вы также узнаете о переключении целевых объектов отрисовки и добавлении эффектов в приложение.

Что такое устройство Direct2D?

Для создания контекста устройства Direct2D и Direct3D требуется устройство Direct2D. Устройство Direct2D (предоставляет указатель интерфейса ID2D1Device) представляет адаптер дисплея. Устройство Direct3D (предоставляет указатель интерфейса ID3D11Device ) связано с устройством Direct2D. Каждое приложение должно иметь одно устройство Direct2D, но может иметь несколько устройств.

Что такое контекст устройства Direct2D?

Контекст устройства Direct2D (предоставляет указатель интерфейса ID2D1DeviceContext) представляет набор буферов состояния и команд, используемых для отрисовки в целевой объект. Методы в контексте устройства можно вызывать для задания состояния конвейера и создания команд отрисовки с помощью ресурсов, принадлежащих устройству.

Отрисовка с помощью Direct2D в Windows 8

В Windows 7 и более ранних версиях используется идентификатор ID2D1HwndRenderTarget или другой целевой интерфейс отрисовки для отрисовки в окне или поверхности. Начиная с Windows 8, мы не рекомендуем выполнять отрисовку с помощью методов, использующих такие интерфейсы, как ID2D1HwndRenderTarget, так как они не будут работать с приложениями Магазина Windows. Вы можете использовать контекст устройства для отрисовки в Hwnd, если вы хотите сделать классическое приложение и по-прежнему воспользоваться дополнительными функциями контекста устройства. Однако контекст устройства необходим для отрисовки содержимого в приложениях Магазина Windows с помощью Direct2D.

Зачем использовать контекст устройства для отрисовки?

  • Вы можете отрисовку для приложений Магазина Windows.
  • Целевой объект отрисовки можно изменить в любое время до, во время и после отрисовки. Контекст устройства гарантирует, что вызовы методов рисования выполняются в порядке и применяются при переключении целевого объекта отрисовки.
  • С контекстом устройства можно использовать несколько типов окон. Вы можете использовать контекст устройства и цепочку буферов DXGI для отрисовки непосредственно в Windows::UI::CoreWindow или Windows::UI::XAML::SwapChainBackgroundPanel.
  • Контекст устройства Direct2D можно использовать для создания эффектов Direct2D и отображения выходных данных эффекта изображения или графа эффектов в целевом объекте отрисовки.
  • Можно использовать несколько контекстов устройств, которые могут быть полезны для повышения производительности в потоковом приложении. Дополнительные сведения см. в многопоточных приложениях Direct2D.
  • Контекст устройства тесно взаимодействует с Direct3D, предоставляя вам больше доступа к параметрам Direct3D.

Создание контекста устройства Direct2D для отрисовки

В приведенном здесь коде показано, как создать устройство Direct3D11, получить связанное устройство DXGI, создать устройство Direct2D и, наконец, создать контекст устройства Direct2D для отрисовки.

Ниже приведена схема вызовов методов и интерфейсов, которые использует этот код.

схема прямых и прямых 3d устройств и контекстов устройств.

Примечание

Этот код предполагает, что у вас уже есть объект ID2D1Factory1, дополнительные сведения см. на странице справочника 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
            )
        );

Давайте рассмотрим шаги, описанные в предыдущем примере кода.

  1. Получите указатель интерфейса ID3D11Device, который потребуется для создания контекста устройства.

  2. Запросите устройство Direct3D 11 для своего интерфейса устройства DXGI.

  3. Создайте объект ID2D1Device, вызвав метод ID2D1Factory::CreateDevice и передавая объект IDXGIDevice.

  4. Создайте указатель ID2D1DeviceContext с помощью метода ID2D1Device::CreateDeviceContext.

Выбор целевого объекта

В приведенном ниже коде показано, как получить 2мерную текстуру Direct3D для буфера заднего окна и создать целевой объект растрового изображения, который связывается с этой текстурой, с которой отображается контекст устройства 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());

Давайте рассмотрим шаги, описанные в предыдущем примере кода.

  1. Выделите структуру DXGI_SWAP_CHAIN_DESC1 и определите параметры для цепочки буферов.

    В этих параметрах показано, как создать цепочку буферов, которую может использовать приложение Магазина Windows.

  2. Получите адаптер, на котором запущено устройство Direct3D и устройство DXGI, и получите связанный с ними объект IDXGIFactory. Эту фабрику DXGI необходимо использовать, чтобы убедиться, что цепочка буферов создается на том же адаптере.

  3. Вызовите метод IDXGIFactory2::CreateSwapChainForCoreWindow, чтобы создать цепочку буферов. Используйте класс Windows::UI::CoreWindow для главного окна приложения Магазина Windows.

    Убедитесь, что максимальная задержка кадров составляет 1, чтобы свести к минимуму потребление энергии.

    Если вы хотите отобразить содержимое Direct2D в приложении Магазина Windows, см. метод CreateSwapChainForComposition.

  4. Получите обратный буфер из цепочки буферов. Обратный буфер предоставляет интерфейс ID3D11Texture2D, выделенный цепочкой буферов.

  5. Объявите структуру D2D1_BITMAP_PROPERTIES1 и задайте значения свойств. Задайте для формата пикселя BGRA, так как это формат устройства Direct3D и используемого устройства DXGI.

  6. Получите обратный буфер в виде IDXGISurface для передачи в Direct2D. Direct2D не принимает идентификатор ID3D11Texture2D напрямую.

    Создайте объект ID2D1Bitmap из заднего буфера с помощью метода ID2D1DeviceContext::CreateBitmapFromDromDxgiSurface.

  7. Теперь растровое изображение Direct2D связано с задним буфером. Задайте целевой объект в контексте устройства Direct2D растровым изображением.

Как отрисовка и отображение

Теперь, когда у вас есть целевой растровый рисунок, вы можете нарисовать в нем примитивы, изображения, эффекты изображения и текст в нем с помощью контекста устройства Direct2D. В этом коде показано, как нарисовать прямоугольник.

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

Давайте рассмотрим шаги, описанные в предыдущем примере кода.

  1. Вызовите CreateSolidColorBrush, чтобы создать кисть для рисования прямоугольника.
  2. Вызовите метод BeginDraw перед выдачой любых команд рисования.
  3. Вызовите метод DrawRectangle прямоугольник для рисования и кисти.
  4. Вызовите метод EndDraw после завершения выдачи команд рисования.
  5. Отображение результата путем вызова метода IDXGISwapChain::P resent .

Теперь можно использовать контекст устройства Direct2D для рисования примитивов, изображений, эффектов изображения и текста на экране.