다음을 통해 공유


Direct2D 디바이스 컨텍스트를 사용하여 렌더링하는 방법

이 항목에서는 Windows 8에서 Direct2D 디바이스 컨텍스트를 만드는 방법을 알아봅니다. 이 정보는 Direct2D를 사용하여 Windows 스토어 앱 또는 데스크톱 앱을 개발하는 경우에 적용됩니다. 이 항목에서는 Direct2D 디바이스 컨텍스트 개체의 목적, 해당 개체를 만드는 방법 및 Direct2D 기본 형식 및 이미지 렌더링 및 표시에 대한 단계별 가이드에 대해 설명합니다. 렌더링 대상을 전환하고 앱에 효과를 추가하는 방법에 대해서도 알아봅니다.

Direct2D 디바이스란?

Direct2D 디바이스 컨텍스트를 만들려면 Direct2D 디바이스와 Direct3D 디바이스가 필요합니다. Direct2D 디바이스(ID2D1Device 인터페이스 포인터 노출)는 디스플레이 어댑터를 나타냅니다. Direct3D 디바이스(ID3D11Device 인터페이스 포인터 노출)는 Direct2D 디바이스와 연결됩니다. 각 앱에는 하나의 Direct2D 디바이스가 있어야 하지만 둘 이상의 디바이스가 있을 수 있습니다.

Direct2D 디바이스 컨텍스트란?

Direct2D 디바이스 컨텍스트(ID2D1DeviceContext 인터페이스 포인터 노출)는 대상에 렌더링하는 데 사용하는 상태 및 명령 버퍼 집합을 나타냅니다. 디바이스 컨텍스트에서 메서드를 호출하여 파이프라인 상태를 설정하고 디바이스가 소유한 리소스를 사용하여 렌더링 명령을 생성할 수 있습니다.

Windows 8에서 Direct2D를 사용하여 렌더링

Windows 7 이하에서는 ID2D1HwndRenderTarget 또는 다른 렌더링 대상 인터페이스를 사용하여 창 또는 화면에 렌더링합니다. Windows 8부터는 WINDOWS 스토어 앱에서 작동하지 않으므로 ID2D1HwndRenderTarget과 같은 인터페이스를 사용하는 메서드를 사용하여 렌더링하지 않는 것이 좋습니다. 데스크톱 앱을 만들고 디바이스 컨텍스트의 추가 기능을 계속 활용하려는 경우 디바이스 컨텍스트를 사용하여 Hwnd에 렌더링할 수 있습니다. 그러나 Direct2D사용하여 Windows 스토어 앱에서 콘텐츠를 렌더링하려면 디바이스 컨텍스트필요합니다.

디바이스 컨텍스트를 사용하여 렌더링하는 이유는 무엇인가요?

  • Windows 스토어 앱용으로 렌더링할 수 있습니다.
  • 렌더링 전, 도중 및 후에 언제든지 렌더링 대상을 변경할 수 있습니다. 디바이스 컨텍스트를 사용하면 그리기 메서드에 대한 호출이 순서대로 실행되고 렌더링 대상을 전환할 때 적용됩니다.
  • 디바이스 컨텍스트에서 둘 이상의 창 유형을 사용할 수 있습니다. 디바이스 컨텍스트DXGI 스왑 체인을 사용하여 Windows::UI::Core::CoreWindow 또는 Windows::UI::XAML::SwapChainBackgroundPanel에 직접 렌더링할 수 있습니다.
  • Direct2D 디바이스 컨텍스트를 사용하여 Direct2D 효과를 만들고 이미지 효과 또는 효과 그래프의 출력을 렌더링 대상에 렌더링할 수 있습니다.
  • 스레드 앱의 성능을 향상시키는 데 도움이 될 수 있는 여러 디바이스 컨텍스트를 가질 수 있습니다. 자세한 내용은 다중 스레드 Direct2D 앱을 참조 하세요 .
  • 디바이스 컨텍스트Direct3D와 긴밀하게 상호 운용되므로 Direct3D 옵션에 더 많이 액세스할 수 있습니다.

렌더링을 위한 Direct2D 디바이스 컨텍스트를 만드는 방법

이 코드에서는 Direct3D11 디바이스를 만들고, 연결된 DXGI 디바이스를 가져와서 Direct2D 디바이스만든 다음, 마지막으로 렌더링을 위한 Direct2D 디바이스 컨텍스트를 만드는 방법을 보여줍니다.

다음은 이 코드에서 사용하는 메서드 호출 및 인터페이스의 다이어그램입니다.

direct2d 및 direct3d 디바이스 및 디바이스 컨텍스트의 다이어그램

 

    // 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. ID2D1Factory::CreateDevice 메서드를 호출하고 IDXGIDevice 개체를 전달하여 ID2D1Device 개체를 만듭니다.

  4. ID2D1Device::CreateDeviceContext 메서드를 사용하여 ID2D1DeviceContext 포인터를 만듭니다.

대상 선택

이 코드에서는 창 뒤로 버퍼에 대한 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 스토어 앱의 주 창에 Windows::UI::CoreWindow 클래스를 사용합니다.

    최대 프레임 대기 시간을 1로 설정하여 전력 소비를 최소화해야 합니다.

    Windows 스토어 앱에서 Direct2D 콘텐츠를 렌더링하려면 CreateSwapChainForComposition 메서드를 참조하세요.

  4. 스왑 체인에서 백 버퍼를 가져옵니다. 백 버퍼는 스왑 체인에 의해 할당된 ID3D11Texture2D 인터페이스를 노출합니다.

  5. D2D1_BITMAP_PROPERTIES1 구조체를 선언하고 속성 값을 설정합니다. Direct3D 디바이스 및 DXGI 디바이스에서 사용하는 형식이므로 픽셀 형식을 BGRA로 설정합니다.

  6. Direct2D에 전달할 IDXGISurface 로 백 버퍼를 가져옵니다. Direct2D는 ID3D11Texture2D직접 수락하지 않습니다.

    ID2D1DeviceContext::CreateBitmapFromDxgiSurface 메서드를 사용하여 백 버퍼에서 ID2D1Bitmap 개체를 만듭니다.

  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 디바이스 컨텍스트 그리기 기본 형식, 이미지, 이미지 효과 및 텍스트를 화면에 사용할 수 있습니다.