다음을 통해 공유


Direct2D 앱의 성능 향상

Direct2D은 하드웨어가 가속화되어 고성능을 위한 것이지만, 처리량을 최대화하려면 이 기능을 올바르게 사용해야 합니다. 여기서 보여 준 기술은 일반적인 시나리오를 연구한 결과이며 모든 앱 시나리오에는 적용되지 않을 수 있습니다. 따라서 앱 동작 및 성능 목표를 신중하게 이해하면 원하는 결과를 달성하는 데 도움이 될 수 있습니다.

리소스 사용량

리소스는 비디오 또는 시스템 메모리에서 일종의 할당입니다. 비트맵 및 브러시는 리소스의 예입니다.

Direct2D에서는 소프트웨어와 하드웨어 모두에서 리소스를 만들 수 있습니다. 하드웨어에서 리소스를 만들고 삭제하는 작업은 비디오 카드와 통신하는 데 많은 오버헤드가 필요하기 때문에 비용이 많이 듭니다. Direct2D가 대상에 콘텐츠를 렌더링하는 방법을 살펴보겠습니다.

Direct2D에서 모든 렌더링 명령은 BeginDraw 호출과 EndDraw호출 사이에 묶입니다. 이러한 호출은 렌더링 대상에 대해 이루어집니다. 렌더링 작업을 호출하기 전에 BeginDraw 메서드를 호출해야 합니다. BeginDraw 호출한 후 컨텍스트는 일반적으로 렌더링 명령의 일괄 처리를 빌드하지만 다음 명령 중 하나가 true가 될 때까지 이러한 명령 처리를 지연합니다.

  • EndDraw이(가)에 발생했습니다. EndDraw 호출되면 일괄 처리된 그리기 작업이 완료되고 작업의 상태가 반환됩니다.
  • Flush명시적으로 호출합니다. Flush 메서드를 사용하면 일괄 처리가 처리되고 보류 중인 모든 명령이 실행됩니다.
  • 렌더링 명령을 포함하는 버퍼가 가득 찼습니다. 이전 두 조건이 충족되기 전에 이 버퍼가 가득 차면 렌더링 명령이 플러시됩니다.

기본 형식이 플러시될 때까지 Direct2D는 비트맵 및 브러시와 같은 해당 리소스에 대한 내부 참조를 유지합니다.

리소스 다시 사용

이미 언급했듯이 리소스 만들기 및 삭제는 하드웨어에서 비용이 많이 듭니다. 따라서 가능하면 리소스를 다시 사용합니다. 게임 개발에서 비트맵 만들기의 예를 들어 보세요. 일반적으로 게임에서 장면을 구성하는 비트맵은 모두 이후 프레임 간 렌더링에 필요한 다양한 변형과 동시에 만들어집니다. 실제 장면 렌더링 및 다시 렌더링 시 이러한 비트맵은 다시 만드는 대신 다시 사용됩니다.

메모

창 크기 조정 작업에는 리소스를 다시 사용할 수 없습니다. 창 크기가 조정되면 호환되는 렌더링 대상과 같은 일부 확장 종속 리소스와 일부 레이어 리소스를 다시 만들어야 합니다. 창 콘텐츠를 다시 그려야 하기 때문입니다. 렌더링된 장면의 전반적인 품질을 유지하는 데 중요할 수 있습니다.

 

플러시 사용 제한

Flush 메서드를 사용하면 일괄 처리된 렌더링 명령이 처리되므로 사용하지 않는 것이 좋습니다. 가장 일반적인 시나리오의 경우 리소스 관리를 Direct2D로 둡니다.

비트맵

앞에서 설명한 것처럼 리소스 만들기 및 삭제는 하드웨어에서 매우 비용이 많이 드는 작업입니다. 비트맵은 자주 사용되는 리소스의 일종입니다. 비디오 카드에 비트맵을 만드는 것은 비용이 많이 듭니다. 다시 사용하면 애플리케이션을 더 빠르게 만들 수 있습니다.

큰 비트맵 만들기

비디오 카드는 일반적으로 최소 메모리 할당 크기를 갖습니다. 이보다 작은 할당이 요청되면 이 최소 크기의 리소스가 할당되고 잉여 메모리가 낭비되고 다른 작업에 사용할 수 없습니다. 많은 작은 비트맵이 필요한 경우 큰 비트맵 하나를 할당하고 이 큰 비트맵에 모든 작은 비트맵 콘텐츠를 저장하는 것이 더 좋습니다. 그런 다음 더 작은 비트맵이 필요한 경우 더 큰 비트맵의 하위 부분을 읽을 수 있습니다. 작업 중에 작은 이미지 간의 상호 작용을 방지하려면 작은 비트맵 사이에 안쪽 여백(투명한 검은색 픽셀)을 포함해야 하는 경우가 많습니다. 이를 아틀라스이라고도 하며 비트맵 생성 오버헤드 및 작은 비트맵 할당의 메모리 낭비를 줄이는 이점이 있습니다. 대부분의 비트맵을 64KB 이상으로 유지하고 4KB보다 작은 비트맵 수를 제한하는 것이 좋습니다.

비트맵의 아틀라스 만들기

비트맵 아틀라스가 매우 잘 처리할 수 있는 몇 가지 일반적인 시나리오가 있습니다. 작은 비트맵은 큰 비트맵 내에 저장할 수 있습니다. 이러한 작은 비트맵은 대상 사각형을 지정하여 필요할 때 더 큰 비트맵에서 끌어올 수 있습니다. 예를 들어 애플리케이션은 여러 아이콘을 그려야 합니다. 아이콘과 연결된 모든 비트맵을 앞에 큰 비트맵으로 로드할 수 있습니다. 렌더링 시 큰 비트맵에서 검색할 수 있습니다.

메모

비디오 메모리에서 만든 Direct2D 비트맵은 저장된 어댑터에서 지원하는 최대 비트맵 크기로 제한됩니다. 너무 큰 비트맵을 만들 경우 오류가 발생할 수 있습니다.

 

메모

Windows 8부터 Direct2D에는 이 프로세스를 더 쉽게 만들 수 있는 아틀라스 효과 포함되어 있습니다.

 

공유 비트맵 만들기

공유 비트맵을 생성하면 렌더 타깃과 이미 호환되는 기존 개체를 직접 활용하여 고급 호출자가 Direct2D 비트맵 개체를 만들 수 있습니다. 이렇게 하면 여러 표면이 생성되는 것을 방지하고 성능 오버헤드를 줄이는 데 도움이 됩니다.

메모

공유 비트맵은 일반적으로 소프트웨어 대상 또는 DXGI와 상호 운용 가능한 대상으로 제한됩니다. CreateBitmapFromDxgiSurface메서드, CreateBitmapFromWicBitmap메서드, 그리고 CreateSharedBitmap 메서드를 사용하여 공유 비트맵을 만듭니다.

 

비트맵 복사

DXGI 표면을 만드는 것은 비용이 많이 드는 작업이므로 가능한 경우 기존 표면을 다시 사용합니다. 소프트웨어에서도 비트맵이 주로 작은 부분을 제외하고 원하는 형식인 경우 전체 비트맵을 버리고 모든 것을 다시 만드는 것보다 해당 부분을 업데이트하는 것이 좋습니다. CreateCompatibleRenderTarget사용하여 동일한 결과를 얻을 수 있지만 렌더링은 일반적으로 복사하는 것보다 훨씬 비용이 많이 드는 작업입니다. 이는 캐시 지역성을 개선하기 위해 하드웨어가 비트맵의 주소를 지정하는 것과 동일한 메모리 순서로 비트맵을 실제로 저장하지 않기 때문입니다. 대신 비트맵이 변형될 수 있습니다. 스위즐링은 드라이버에 의해 숨겨지거나, GPU의 메모리 관리자가 수행하여 CPU에서는 보이지 않게 됩니다. 드라이버 방식은 느리고 저사양 부품에서만 사용됩니다. 렌더링할 때 데이터가 렌더링 대상에 기록되는 방식에 대한 제약 조건으로 인해 렌더링 대상은 일반적으로 스위즐되지 않거나, 화면에 렌더링할 필요가 없다는 것을 알고 있을 때 달성할 수 있는 것보다 덜 최적화된 방식으로 스위즐됩니다. 따라서 원본에서 Direct2D 비트맵으로 사각형을 복사하기 위해 CopyFrom* 메서드가 제공됩니다.

CopyFrom은 다음 세 가지 형식 중에서 사용할 수 있습니다.

대시 대신 타일형 비트맵 사용

파선 렌더링은 기본 알고리즘의 높은 품질과 정확도 때문에 매우 비용이 많이 드는 작업입니다. 직사각형 기하 도형을 포함하지 않는 대부분의 경우 타일식 비트맵을 사용하여 동일한 효과를 더 빠르게 생성할 수 있습니다.

복잡한 정적 콘텐츠를 렌더링하기 위한 일반적인 지침

프레임 위에 동일한 콘텐츠 프레임을 렌더링하는 경우, 특히 장면이 복잡한 경우 콘텐츠를 캐시합니다.

사용할 수 있는 세 가지 캐싱 기술이 있습니다.

  • 색 비트맵을 사용하여 전체 장면 캐싱
  • 기본 캐싱을 위해 A8 비트맵과 FillOpacityMask 메서드를 사용하여.
  • 기하 도형 실현을 사용하는 기본형별 캐싱입니다.

이러한 각 내용을 자세히 살펴보겠습니다.

색 비트맵을 사용하여 전체 장면 캐싱

애니메이션과 같은 시나리오에서 정적 콘텐츠를 렌더링할 때 화면 비트맵에 직접 쓰는 대신 다른 전체 색 비트맵을 만듭니다. 현재 대상을 저장하고, 대상을 중간 비트맵으로 설정하고, 정적 콘텐츠를 렌더링합니다. 그런 다음 원래 화면 비트맵으로 다시 전환하고 중간 비트맵을 그립니다.

예제는 다음과 같습니다.

// Create a bitmap.
m_d2dContext->CreateBitmap(size, nullptr, 0,
    D2D1::BitmapProperties(
        D2D1_BITMAP_OPTIONS_TARGET,
        D2D1::PixelFormat(
            DXGI_FORMAT_B8G8R8A8_UNORM,
            D2D1_ALPHA_MODE_PREMULTIPLIED),
        dpiX, dpiY),
    &sceneBitmap);

// Preserve the pre-existing target.
ComPtr<ID2D1Image> oldTarget;
m_d2dContext->GetTarget(&oldTarget);

// Render static content to the sceneBitmap.
m_d2dContext->SetTarget(sceneBitmap.Get());
m_d2dContext->BeginDraw();
…
m_d2dContext->EndDraw();

// Render sceneBitmap to oldTarget.
m_d2dContext->SetTarget(oldTarget.Get());
m_d2dContext->DrawBitmap(sceneBitmap.Get());

이 예제에서는 캐싱에 중간 비트맵을 사용하고 디바이스 컨텍스트가 렌더링할 때 가리키는 비트맵을 전환합니다. 이렇게 하면 동일한 용도로 호환되는 렌더링 대상을 만들 필요가 없습니다.

A8 비트맵과 FillOpacityMask 메서드를 사용하는 기본 프리미티브 캐싱

전체 장면이 정적이지는 않지만 기하 도형 또는 정적 텍스트와 같은 요소로 구성된 경우 기본 캐싱 기법을 사용할 수 있습니다. 이 기술은 캐시되는 기본 형식의 앤티앨리어싱 특성을 보존하고 브러시 형식 변경과 함께 작동합니다. A8 비트맵을 사용합니다. 여기서 A8은 8비트가 있는 알파 채널을 나타내는 일종의 픽셀 형식입니다. A8 비트맵은 기하 도형/텍스트를 마스크로 그리는 데 유용합니다. 콘텐츠 자체를 조작하는 대신 정적 콘텐츠의 불투명도를 조작해야 하는 경우 마스크의 불투명도를 변환, 회전, 기울이기 또는 스케일링할 수 있습니다.

예제는 다음과 같습니다.

// Create an opacity bitmap.
m_d2dContext->CreateBitmap(size, nullptr, 0,
    D2D1::BitmapProperties(
        D2D1_BITMAP_OPTIONS_TARGET,
        D2D1::PixelFormat(
            DXGI_FORMAT_A8_UNORM,
            D2D1_ALPHA_MODE_PREMULTIPLIED),
        dpiX, dpiY),
    &opacityBitmap);

// Preserve the pre-existing target.
ComPtr<ID2D1Image> oldTarget;
m_d2dContext->GetTarget(&oldTarget);

// Render to the opacityBitmap.
m_d2dContext->SetTarget(opacityBitmap.Get());
m_d2dContext->BeginDraw();
…
m_d2dContext->EndDraw();

// Call the FillOpacityMask method
// Note: for this call to work correctly the anti alias mode must be D2D1_ANTIALIAS_MODE_ALIASED. 
m_d2dContext->SetTarget(oldTarget.Get());
m_d2dContext->FillOpacityMask(
    opacityBitmap.Get(),
    m_contentBrush().Get(),
    D2D1_OPACITY_MASK_CONTENT_GRAPHICS);

기하학적 구현을 이용한 개별 기본형 캐싱

기하 도형 실현이라고 하는 또 다른 기본형 캐싱 기술은 기하 도형을 처리할 때 더 큰 유연성을 제공합니다. 에일리어스 또는 안티에일리어스화된 기하 도형을 반복적으로 그리려는 경우, 기하 도형을 기하학 실현으로 변환하고 변환된 실현을 반복적으로 그리는 것이 도형 자체를 반복적으로 그리는 것보다 더 빠릅니다. 또한 기하 도형 실현은 일반적으로 불투명 마스크(특히 큰 기하 도형의 경우)보다 메모리를 적게 소비하며 배율 변경에 덜 민감합니다. 자세한 내용을 보려면 Geometry Realizations Overview을 참조하세요.

예제는 다음과 같습니다.

    // Compute a flattening tolerance based on the scales at which the realization will be used.
    float flatteningTolerance = D2D1::ComputeFlatteningTolerance(...);

    ComPtr<ID2D1GeometryRealization> geometryRealization;

    // Create realization of the filled interior of the geometry.
    m_d2dDeviceContext1->CreateFilledGeometryRealization(
        geometry.Get(),
        flatteningTolerance,
        &geometryRealization
        );

    // In your app's rendering code, draw the geometry realization with a brush.
    m_d2dDeviceContext1->BeginDraw();
    m_d2dDeviceContext1->DrawGeometryRealization(
        geometryRealization.Get(),
        m_brush.Get()
        );
    m_d2dDeviceContext1->EndDraw();

기하학 렌더링

그리기 기하학보다 구체적인 그리기 기본 형식을 사용하십시오.

제네릭 DrawGeometry 호출 대신, DrawRectangle 같은 더 구체적인 그리기기본 호출을 사용하십시오. 이는 DrawRectangle기하 도형이 이미 알려져 있으므로 렌더링 속도가 빠르기 때문입니다.

정적 기하 도형 렌더링

기하 도형이 정적인 시나리오에서는 위에서 설명한 기본형별 캐싱 기술을 사용합니다. 불투명 마스크 및 기하 도형 실현은 정적 기하 도형을 포함하는 장면의 렌더링 속도를 크게 향상시킬 수 있습니다.

다중 스레드 디바이스 컨텍스트 사용

상당한 양의 복잡한 기하학적 콘텐츠를 렌더링해야 하는 애플리케이션은 Direct2D 디바이스 컨텍스트를 만들 때 D2D1_DEVICE_CONTEXT_OPTIONS_ENABLE_MULTI_THREADED_OPTIMIZATIONS 플래그를 지정하는 것이 좋습니다. 이 플래그를 지정하면 Direct2D는 시스템에 있는 모든 논리 코어에 렌더링을 분산하여 전체 렌더링 시간을 크게 줄일 수 있습니다.

노트:

  • Windows 8.1을 기준으로 이 플래그는 경로 기하 도형 렌더링에만 영향을 줍니다. 다른 기본 형식(예: 텍스트, 비트맵 또는 기하 도형 실현)만 포함하는 장면에는 영향을 주지 않습니다.
  • 이 플래그는 소프트웨어에서 렌더링할 때(즉, WARP Direct3D 디바이스로 렌더링할 때) 영향을 주지 않습니다. 소프트웨어 다중 스레딩을 제어하려면 호출자는 WARP Direct3D 디바이스를 만들 때 D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS 플래그를 사용해야 합니다.
  • 이 플래그를 지정하면 렌더링 중에 최대 작업 집합이 늘어나고 이미 다중 스레드 처리를 활용하는 애플리케이션에서 스레드 경합이 증가할 수 있습니다.

Direct2D를 사용하여 텍스트 그리기

Direct2D 텍스트 렌더링 기능은 두 부분으로 제공됩니다. ID2D1RenderTarget::DrawTextID2D1RenderTarget::DrawTextLayout 메서드로 노출되는 첫 번째 부분은 호출자가 여러 형식에 대해 문자열과 서식 매개 변수 또는 DWrite 텍스트 레이아웃 개체를 전달할 수 있도록 합니다. 이는 대부분의 호출자에게 적합해야 합니다. ID2D1RenderTarget::DrawGlyphRun 메서드로 노출되는 텍스트를 렌더링하는 두 번째 방법은 렌더링하려는 글리프의 위치를 이미 알고 있는 고객에게 래스터화를 제공합니다. 다음 두 가지 일반 규칙은 Direct2D에서 그릴 때 텍스트 성능을 향상시키는 데 도움이 될 수 있습니다.

DrawTextLayout 대 DrawText

DrawTextDrawTextLayout 모두 애플리케이션이 DirectWrite API로 서식이 지정된 텍스트를 쉽게 렌더링할 수 있습니다. DrawTextLayoutRenderTarget에 기존 개체를 그리는 DWriteTextLayout을 실행하고, DrawText는 전달된 매개변수에 따라 호출자에 대한 DirectWrite 레이아웃을 생성합니다. 동일한 텍스트를 여러 번 렌더링해야 하는 경우 drawText 대신 DrawTextLayout 사용합니다. DrawText 호출될 때마다 레이아웃을 만들기 때문입니다.

올바른 텍스트 렌더링 모드 선택

텍스트 앤티앨리어스 모드를 명시적으로 D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE 설정합니다. 회색조 텍스트를 렌더링하는 품질은 ClearType과 비슷하지만 훨씬 빠릅니다.

캐시 저장

다른 도형 그리기와 같이 전체 장면 또는 도형별로 비트맵 캐시를 사용합니다.

임의 모양 자르기

다음은 이미지에 클립을 적용한 결과를 보여 주는 그림입니다.

클립 전후 예시를 보여주는 이미지 .

기하 도형 마스크가 있는 레이어나 불투명 브러시가 있는 FillGeometry 메서드를 사용하여 이 결과를 얻을 수 있습니다.

계층을 사용하는 예제는 다음과 같습니다.

// Call PushLayer() and pass in the clipping geometry.
m_d2dContext->PushLayer(
    D2D1::LayerParameters(
        boundsRect,
        geometricMask));

다음은 FillGeometry 메서드를 사용하는 예제입니다.

// Create an opacity bitmap and render content.
m_d2dContext->CreateBitmap(size, nullptr, 0,
    D2D1::BitmapProperties(
        D2D1_BITMAP_OPTIONS_TARGET,
        D2D1::PixelFormat(
            DXGI_FORMAT_A8_UNORM,
            D2D1_ALPHA_MODE_PREMULTIPLIED),
        dpiX, dpiY),
    &opacityBitmap);

m_d2dContext->SetTarget(opacityBitmap.Get());
m_d2dContext->BeginDraw();
…
m_d2dContext->EndDraw();

// Create an opacity brush from the opacity bitmap.
m_d2dContext->CreateBitmapBrush(opacityBitmap.Get(),
    D2D1::BitmapBrushProperties(),
    D2D1::BrushProperties(),
    &bitmapBrush);

// Call the FillGeometry method and pass in the clip geometry and the opacity brush
m_d2dContext->FillGeometry( 
    clipGeometry.Get(),
    brush.Get(),
    opacityBrush.Get()); 

이 코드 예제에서는 PushLayer 메서드를 호출할 때 앱에서 만든 계층을 전달하지 않습니다. Direct2D는 사용자를 위한 레이어를 만듭니다. Direct2D는 앱의 개입 없이 이 리소스의 할당 및 소멸을 관리할 수 있습니다. 이를 통해 Direct2D는 내부적으로 계층을 다시 사용하고 리소스 관리 최적화를 적용할 수 있습니다.

Windows 8에서는 레이어 사용에 대한 많은 최적화가 이루어졌으며, 가능한 한 FillGeometry대신 레이어 API를 사용하는 것이 좋습니다.

Windows 8의 PushLayer

ID2D1DeviceContext 인터페이스는 ID2D1RenderTarget 인터페이스에서 파생되며 Windows 8에서 Direct2D 콘텐츠를 표시하는 데 핵심적인 요소입니다. 이 인터페이스에 대한 자세한 내용은 디바이스 및 디바이스 컨텍스트참조하세요. 디바이스 컨텍스트 인터페이스를 사용하면 CreateLayer 메서드 호출을 건너뛰고 ID2D1DeviceContext::P ushLayer 메서드에 NULL을 전달할 수 있습니다. Direct2D는 레이어 리소스를 자동으로 관리하고 계층과 효과 그래프 간에 리소스를 공유할 수 있습니다.

축 정렬 클립

클리핑할 영역이 임의가 아닌 그리기 표면의 축에 정렬되는 경우 이 사례는 레이어 대신 클립 사각형을 사용하는 데 적합합니다. 에일리어싱된 기하 도형에서의 성능 향상이 앤티에일리어싱된 기하 도형에서보다 더 큽니다. 축 맞춤 클립에 대한 자세한 내용은 PushAxisAlignedClip 항목을 참조하세요.

DXGI 상호 운용성: 빈번한 스위치 방지

Direct2D는 Direct3D 표면과 원활하게 상호 운용할 수 있습니다. 이는 2D 및 3D 콘텐츠의 혼합을 렌더링하는 애플리케이션을 만드는 데 매우 유용합니다. 그러나 Direct2D와 Direct3D 콘텐츠 그리기 간의 각 전환은 성능에 영향을 줍니다.

DXGI 화면으로 렌더링할 때 Direct2D는 렌더링하는 동안 Direct3D 디바이스의 상태를 저장하고 렌더링이 완료되면 복원합니다. Direct2D 렌더링 일괄 처리가 완료될 때마다 이 저장 및 복원 비용과 모든 2D 작업을 플러시하는 비용이 지불되지만 Direct3D 디바이스는 플러시되지 않습니다. 따라서 성능을 향상시키려면 Direct2D와 Direct3D 간의 렌더링 스위치 수를 제한합니다.

픽셀 형식 파악

렌더링 대상을 만들 때 렌더링 대상에서 사용하는 픽셀 형식과 알파 모드를 지정하는 D2D1_PIXEL_FORMAT 구조를 사용할 수 있습니다. 알파 채널은 검사 값 또는 불투명도 정보를 지정하는 픽셀 형식의 일부입니다. 렌더링 대상에서 알파 채널을 사용하지 않는 경우 D2D1_ALPHA_MODE_IGNORE 알파 모드를 사용하여 만들어야 합니다. 이렇게 하면 필요하지 않은 알파 채널을 렌더링하는 데 소요되는 시간이 절약됩니다.

픽셀 형식 및 알파 모드에 대한 자세한 내용은 지원되는 픽셀 형식 및 알파 모드 참조하세요.

장면 복잡성

렌더링될 장면에서 성능 핫스폿을 분석할 때 장면이 채우기 속도 바인딩인지 또는 꼭짓점 바인딩인지를 알면 유용한 정보를 제공할 수 있습니다.

  • 채우기 비율: 채우기 비율은 그래픽 카드가 렌더링하고 초당 비디오 메모리에 쓸 수 있는 픽셀 수를 나타냅니다.
  • 꼭짓점 경계: 장면에 많은 복잡한 지오메트리가 있을 때, 장면이 꼭짓점에 의해 제한됩니다.

장면 복잡성 이해

렌더링 대상의 크기를 변경하여 장면 복잡성을 분석할 수 있습니다. 렌더링 대상의 크기가 비례적으로 줄어들 때 성능 향상이 눈에 띈다면, 애플리케이션은 채우기 속도에 의해 제한됩니다. 그렇지 않으면 장면 복잡성이 성능 병목 현상입니다.

장면이 채우기 속도에 바인딩된 경우 렌더링 대상의 크기를 줄이면 성능이 향상될 수 있습니다. 렌더링할 픽셀 수가 렌더링 대상의 크기에 비례하여 감소하기 때문입니다.

장면이 꼭짓점에 묶인 경우 기하학의 복잡성을 줄입니다. 그러나 이것은 이미지 품질을 희생하여 수행된다는 것을 기억하십시오. 따라서 원하는 품질과 필요한 성능 간에 신중한 절충 결정을 내려야 합니다.

Direct2D 인쇄 앱의 성능 향상

Direct2D 인쇄와의 호환성을 제공합니다. 직접 그리는 장치나 그림이 인쇄로 변환되는 방법을 모를 경우에도, 동일한 Direct2D 그리기 명령(Direct2D 명령 목록 형식)을 Direct2D 인쇄 컨트롤로 보내 인쇄할 수 있습니다.

Direct2D 인쇄 컨트롤 및 Direct2D 그리기 명령의 사용을 더욱 세부적으로 조정하여 더 나은 성능으로 인쇄 결과를 제공할 수 있습니다.

Direct2D 인쇄 컨트롤은 인쇄 품질 또는 성능 저하(예: 이 항목의 뒷부분에 나열된 코드 패턴)로 이어지는 Direct2D 코드 패턴이 표시되면 디버그 메시지를 출력하여 성능 문제를 방지할 수 있는 위치를 알려 줍니다. 이러한 디버그 메시지를 보려면 코드에서 Direct2D 디버그 계층 사용하도록 설정해야 합니다. 디버그 메시지 출력을 사용하도록 설정하는 지침은 디버그 메시지 참조하세요.

D2D 인쇄 컨트롤을 만들 때 올바른 속성 값 설정

Direct2D 인쇄 컨트롤을 만들 때 설정할 수 있는 세 가지 속성이 있습니다. 이러한 속성 중 두 가지는 Direct2D 인쇄 컨트롤이 특정 Direct2D 명령을 처리하는 방식에 영향을 줍니다. 그러면 전체 성능에 영향을 줍니다.

  • 글꼴 하위 집합 모드: Direct2D 인쇄 컨트롤은 각 페이지를 인쇄하기 전에 페이지에서 사용되는 글꼴 리소스를 하위 집합으로 만듭니다. 이 모드는 인쇄에 필요한 페이지 리소스의 크기를 줄입니다. 페이지의 글꼴 사용량에 따라 최상의 성능을 위해 다른 글꼴 하위 집합 모드를 선택할 수 있습니다.
    • D2D1_PRINT_FONT_SUBSET_MODE_DEFAULT 대부분의 경우 최상의 인쇄 성능을 제공합니다. 이 모드로 설정하면 Direct2D 인쇄 컨트롤은 추론 전략을 사용하여 글꼴을 하위 설정할 시기를 결정합니다.
    • 1~2페이지의 짧은 인쇄 작업의 경우 D2D1_PRINT_FONT_SUBSET_MODE_EACHPAGE 것이 좋습니다. 여기서 Direct2D는 컨트롤 하위 집합을 인쇄하고 각 페이지에 글꼴 리소스를 포함하는 페이지 인쇄 후 해당 글꼴 하위 집합을 삭제합니다. 이 옵션을 사용하면 각 페이지를 생성한 직후에 인쇄할 수 있지만 인쇄에 필요한 페이지 리소스의 크기가 약간 증가합니다(일반적으로 글꼴 하위 집합이 큰 경우).
    • 텍스트 페이지가 많고 글꼴 크기가 작은 인쇄 작업의 경우(예: 단일 글꼴을 사용하는 텍스트 100페이지)의 경우 Direct2D 인쇄 컨트롤에서 글꼴 리소스를 전혀 하위 설정하지 않는 D2D1_PRINT_FONT_SUBSET_MODE_NONE것이 좋습니다. 대신 먼저 글꼴을 사용하는 페이지와 함께 원래 글꼴 리소스를 보내고, 글꼴 리소스를 다시 보내지 않고 이후 페이지에 다시 사용합니다.
  • 래스터화 DPI: Direct2D 인쇄 컨트롤이 Direct2D-XPS 변환 중에 Direct2D 명령을 래스터화해야 하는 경우 래스터화에 이 DPI를 사용합니다. 즉, 페이지에 래스터화된 콘텐츠가 없으면 DPI를 설정해도 성능과 품질이 변경되지 않습니다. 페이지의 래스터화 사용량에 따라 충실도와 성능 간의 최상의 균형을 위해 다른 래스터화 DPI를 선택할 수 있습니다.
    • Direct2D 인쇄 컨트롤을 만들 때 값을 지정하지 않으면 150이 기본값으로, 대부분의 경우 인쇄 품질과 인쇄 성능이 가장 잘 조정됩니다.
    • DPI 값이 높을수록 일반적으로 인쇄 품질이 향상되지만(자세한 내용은 유지됨) 생성되는 비트맵이 클수록 성능이 저하됩니다. 300보다 큰 DPI 값은 사람의 눈으로 시각적으로 인식할 수 있는 추가 정보를 도입하지 않으므로 권장되지 않습니다.
    • DPI가 낮을수록 성능이 향상되지만 품질도 낮아질 수 있습니다.

특정 Direct2D 그리기 패턴을 사용하지 마십시오.

Direct2D 시각적으로 나타낼 수 있는 인쇄 하위 시스템이 전체 인쇄 파이프라인을 따라 유지 관리하고 전송할 수 있는 항목 간에는 차이가 있습니다. Direct2D 인쇄 컨트롤은 인쇄 하위 시스템이 기본적으로 지원하지 않는 Direct2D 기본 형식을 근사화하거나 래스터화하여 이러한 격차를 해소합니다. 이러한 근사치로 인해 일반적으로 인쇄 품질이나 성능이 낮아지게 됩니다. 따라서 고객이 화면 및 인쇄 렌더링 모두에 동일한 그리기 패턴을 사용할 수 있지만 모든 경우에 이상적이지는 않습니다. 이러한 Direct2D 기본 형식 및 패턴을 인쇄 경로에 최대한 많이 사용하지 않거나 래스터화된 이미지의 품질과 크기를 완전히 제어할 수 있는 래스터화를 소유하는 것이 가장 좋습니다.

다음은 인쇄 성능 및 품질이 이상적이지 않고 최적의 인쇄 성능을 위해 코드 경로를 변경하는 것을 고려할 수 있는 사례 목록입니다.

  • D2D1_PRIMITIVE_BLEND_SOURCEOVER이외의 기본 혼합 모드를 사용하지 않습니다.
  • D2D1_COMPOSITE_MODE_SOURCE_OVERD2D1_COMPOSITE_MODE_DESTINATION_OVER이외의 이미지를 그릴 때에는 컴퍼지션 모드를 사용하지 마십시오.
  • GDI 메타 파일을 그리지 마세요.
  • 원본 배경을 복사하는 레이어 리소스를 푸시하지 마세요(D2D1_LAYER_PARAMETERS1 구조체에 D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND 전달하여 PushLayer 호출).
  • D2D1_EXTEND_MODE_CLAMP 사용하여 비트맵 브러시 또는 이미지 브러시를 만들지 마세요. 이미지 바깥쪽의 픽셀에 전혀 신경 쓰지 않는 경우(예: 브러시에 연결된 이미지가 채워진 대상 영역보다 큰 것으로 알려진 경우) D2D1_EXTEND_MODE_MIRROR를 사용하는 것이 좋습니다.
  • 원근 변환비트맵을 그리지 마십시오.

직접적이고 평범한 방식으로 텍스트 그리기

Direct2D에는 더 나은 성능 및/또는 더 나은 시각적 품질을 위해 표시할 텍스트를 렌더링할 때 몇 가지 최적화가 있습니다. 그러나 용지 인쇄가 일반적으로 훨씬 더 높은 DPI에 있으므로 인쇄 성능과 품질이 향상되는 것은 아니며 인쇄는 애니메이션과 같은 시나리오를 수용할 필요가 없습니다. 따라서 원본 텍스트 또는 문자 모양을 직접 그리고 인쇄를 위한 명령 목록을 만들 때 다음 최적화를 사용하지 않는 것이 좋습니다.

  • FillOpacityMask 메서드를 사용하여 텍스트를 그리지 않습니다.
  • 별칭 모드에서 텍스트를 그리는 것을 피하십시오.

가능하면 원래 비트맵 그리기

대상 비트맵이 JPEG, PNG, TIFF 또는 JPEG-XR인 경우 디스크 파일 또는 메모리 내 스트림에서 WIC 비트맵을 만든 다음, ID2D1DeviceContext::CreateBitmapFromWicBitmap사용하여 해당 WIC 비트맵에서 Direct2D 비트맵을 만들고, 마지막으로 추가 조작 없이 Direct2D 비트맵을 Direct2D 인쇄 컨트롤에 직접 전달할 수 있습니다. 이렇게 하면 Direct2D 인쇄 컨트롤은 비트맵 스트림을 다시 사용할 수 있으며, 이는 일반적으로 더 나은 인쇄 성능(중복 비트맵 인코딩 및 디코딩 건너뛰기) 및 더 나은 인쇄 품질(비트맵에서 색 프로필과 같은 메타데이터가 유지되는 경우)으로 이어집니다.

원래 비트맵을 그리면 애플리케이션에 다음과 같은 이점이 제공됩니다.

  • 일반적으로 Direct2D 인쇄는 파이프라인의 후반부까지 원본 정보(손실 또는 노이즈 없이)를 유지합니다. 특히 앱이 인쇄 파이프라인의 세부 정보(예: 인쇄할 프린터, 대상 프린터인 DPI 등)를 모를 때 특히 그렇습니다.
  • 대부분의 경우 비트맵 래스터화를 지연하면 성능이 향상됩니다(예: 96dpi 사진을 600dpi 프린터로 인쇄할 때).
  • 경우에 따라 원본 이미지를 전달하는 것이 고화질(예: 포함된 색 프로필)을 적용하는 유일한 방법입니다.

그러나 다음과 같은 이유로 이러한 최적화를 옵트인할 수 없습니다.

  • 프린터 정보 및 초기 래스터화를 쿼리하여 용지의 최종 모양을 완전히 제어하여 콘텐츠 자체를 래스터화할 수 있습니다.
  • 경우에 따라 초기 래스터화는 실제로 앱의 엔드 투 엔드 성능(예: 지갑 크기 사진 인쇄)을 향상시킬 수 있습니다.
  • 특정 경우에 원래 비트맵을 전달하려면 기존 코드 아키텍처(예: 이미지 지연 로드 및 특정 애플리케이션에서 찾은 리소스 업데이트 경로)를 크게 변경해야 합니다.

결론

Direct2D는 하드웨어가 가속화되고 고성능을 위한 것이지만, 처리량을 최대화하려면 이 기능을 올바르게 사용해야 합니다. 여기서 살펴본 기술은 일반적인 시나리오를 공부하면서 파생되며 모든 애플리케이션 시나리오에는 적용되지 않을 수 있습니다.