Поделиться через


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

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

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

Для создания контекста устройства Direct2D требуется устройство Direct2D и устройство Direct3D. Устройство 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 для отрисовки.

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

схема устройств и контекстов устройств Direct2D и Direct3D.

Примечание.

Этот код предполагает, что у вас уже есть объект 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. Запросите интерфейс DXGI устройства Direct3D 11.

  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, который выделен при помощи swap chain.

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

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

    Создайте объект ID2D1Bitmap из заднего буфера, используя метод ID2D1DeviceContext::CreateBitmapFromDxgiSurface.

  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::Present.

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