Direct2D 앱의 성능 향상
Direct2D는 하드웨어가 가속화되고 고성능을 위한 것이지만 처리량을 최대화하려면 기능을 올바르게 사용해야 합니다. 여기서 보여 준 기술은 일반적인 시나리오를 연구한 결과이며 모든 앱 시나리오에는 적용되지 않을 수 있습니다. 따라서 앱 동작 및 성능 목표를 신중하게 이해하면 원하는 결과를 달성하는 데 도움이 될 수 있습니다.
- 리소스 사용량
- 플러시 사용 제한
- 비트맵
- 대시 위에 타일형 비트맵 사용
- 복잡한 정적 콘텐츠를 렌더링하기 위한 일반 지침
- 기하 도형 실현을 사용한 기본형별 캐싱
- 기하 도형 렌더링
- Direct2D를 사용하여 텍스트 그리기
- 임의의 셰이프 클리핑
- DXGI 상호 운용성: 빈번한 스위치 방지
- 픽셀 형식 파악
- 장면 복잡성
- 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 실현 개요를 참조하세요.
예를 들면 다음과 같습니다.
// 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::D rawText 및 ID2D1RenderTarget::D rawTextLayout 메서드로 노출되는 첫 번째 부분은 호출자가 여러 형식에 대해 문자열 및 서식 매개 변수 또는 DWrite 텍스트 레이아웃 개체를 전달할 수 있도록 합니다. 대부분의 호출자에게 적합합니다. ID2D1RenderTarget::D rawGlyphRun 메서드로 노출되는 텍스트를 렌더링하는 두 번째 방법은 렌더링하려는 문자 모양의 위치를 이미 알고 있는 고객에게 래스터화를 제공합니다. 다음 두 가지 일반적인 규칙은 Direct2D에서 그릴 때 텍스트 성능을 향상시키는 데 도움이 될 수 있습니다.
DrawTextLayout 및 DrawText
DrawText 및 DrawTextLayout을 모두 사용하면 애플리케이션이 DirectWrite API로 서식이 지정된 텍스트를 쉽게 렌더링할 수 있습니다. DrawTextLayout은 기존 DWriteTextLayout 개체를 RenderTarget에 그리고 DrawText는 전달되는 매개 변수를 기반으로 호출자에 대한 DirectWrite 레이아웃을 생성합니다. 동일한 텍스트를 여러 번 렌더링해야 하는 경우 DrawText가 호출될 때마다 레이아웃을 만들기 때문에 DrawText 대신DrawTextLayout을 사용합니다.
올바른 텍스트 렌더링 모드 선택
텍스트 앤티앨리어스 모드를 명시적으로 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 푸시레이어
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페이지의 짧은 인쇄 작업의 경우 direct2D 인쇄 컨트롤 하위 집합이 각 페이지에 글꼴 리소스를 포함하고 페이지 인쇄 후 해당 글꼴 하위 집합을 삭제하는 D2D1_PRINT_FONT_SUBSET_MODE_EACHPAGE 것이 좋습니다. 이 옵션을 사용하면 각 페이지를 생성한 직후에 인쇄할 수 있지만 인쇄에 필요한 페이지 리소스의 크기가 약간 증가합니다(일반적으로 글꼴 하위 집합이 큰 경우).
- 텍스트 페이지가 많고 글꼴 크기가 작은 인쇄 작업(예: 단일 글꼴을 사용하는 텍스트 100페이지)의 경우 Direct2D 인쇄 컨트롤이 글꼴 리소스를 전혀 하위 설정하지 않는 D2D1_PRINT_FONT_SUBSET_MODE_NONE 것이 좋습니다. 대신 글꼴을 처음 사용하는 페이지와 함께 원래 글꼴 리소스를 보내고, 글꼴 리소스를 다시 보내지 않고 이후 페이지에 다시 사용합니다.
- 래스터화 DPI: Direct2D-XPS 변환 중에 Direct2D 인쇄 컨트롤이 Direct2D 명령을 래스터화해야 하는 경우 이 DPI를 래스터화에 사용합니다. 즉, 페이지에 래스터화된 콘텐츠가 없으면 DPI를 설정해도 성능과 품질이 변경되지 않습니다. 페이지의 래스터화 사용량에 따라 충실도와 성능 간의 최상의 균형을 위해 다양한 래스터화 DPI를 선택할 수 있습니다.
- Direct2D 인쇄 컨트롤을 만들 때 값을 지정하지 않으면 150이 기본값으로, 대부분의 경우 인쇄 품질과 인쇄 성능의 균형을 가장 잘 조정합니다.
- DPI 값이 높을수록 일반적으로 인쇄 품질이 향상되지만(자세한 내용은 유지됨) 더 큰 비트맵으로 인해 성능이 저하됩니다. 300보다 큰 DPI 값은 사람의 눈으로 시각적으로 인식할 수 있는 추가 정보를 도입하지 않으므로 권장하지 않습니다.
- DPI가 낮을수록 성능이 향상되지만 품질도 낮아질 수 있습니다.
특정 Direct2D 그리기 패턴 사용 방지
Direct2D가 시각적으로 나타낼 수 있는 것과 인쇄 하위 시스템이 전체 인쇄 파이프라인을 따라 유지 관리하고 전송할 수 있는 항목 간에는 차이가 있습니다. Direct2D 인쇄 컨트롤은 인쇄 하위 시스템이 기본적으로 지원하지 않는 Direct2D 기본 형식을 근사화하거나 래스터화하여 이러한 격차를 해소합니다. 이러한 근사치로 인해 일반적으로 인쇄 충실도가 낮아지거나 인쇄 성능이 낮아지거나 둘 다 발생합니다. 따라서 고객이 화면 및 인쇄 렌더링 모두에 동일한 그리기 패턴을 사용할 수 있지만 모든 경우에 이상적이지는 않습니다. 이러한 Direct2D 기본 형식 및 패턴을 인쇄 경로에 최대한 많이 사용하지 않거나 래스터화된 이미지의 품질과 크기를 완전히 제어할 수 있는 래스터화를 소유하는 것이 가장 좋습니다.
다음은 인쇄 성능과 품질이 이상적이지 않고 최적의 인쇄 성능을 위해 코드 경로를 다양하게 고려할 수 있는 사례 목록입니다.
- D2D1_PRIMITIVE_BLEND_SOURCEOVER 이외의 기본 혼합 모드를 사용하지 않습니다.
- D2D1_COMPOSITE_MODE_SOURCE_OVER 및 D2D1_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는 하드웨어가 가속화되고 고성능을 위한 것이지만 처리량을 최대화하려면 기능을 올바르게 사용해야 합니다. 여기서 살펴본 기술은 일반적인 시나리오를 공부하면서 파생되었으며 모든 애플리케이션 시나리오에는 적용되지 않을 수 있습니다.