Skip to content

Latest commit

 

History

History
51 lines (31 loc) · 7.34 KB

common_pitfalls.adoc

File metadata and controls

51 lines (31 loc) · 7.34 KB

신규 Vulkan 개발자를 위한 일반적인 함정

이것은 Vulkan API의 가정, 함정, 안티패턴에 대한 짧은 목록입니다. 이 목록은 “모범 사례” 목록이 아니라 Vulkan을 처음 접하는 개발자가 범하기 쉬운 일반적인 실수를 다루고 있습니다.

검증 레이어(Validation Layers)

개발 중에는 유효성 검사 레이어가 활성화되어 있는지 확인하세요. 유효성 검사 레이어는 Vulkan API를 사용하는 동안 실수를 잡아내는 매우 유용한 도구입니다. 매개변수 검사, 객체 수명, 스레딩 위반은 모두 제공되는 오류 검사의 일부입니다. 이러한 기능이 활성화되어 있는지 확인하는 방법은 출력 스트림에 “Debug Messenger Added” 라는 텍스트가 있는지 확인하는 것입니다. 자세한 내용은 Vulkan SDK 레이어 문서에서 확인할 수 있습니다.

Vulkan은 도구 상자일 뿐입니다(Vulkan Is a Box of Tools)

Vulkan에서는 대부분의 문제를 여러 가지 방법으로 대처할 수 있으며 각각 장단점이 있습니다. “완벽한” 해결책은 거의 없으며, 해결책을 찾는데 집착하는 것은 무익한 노력될 수 있습니다. 문제에 직면했을 때는 현재의 요구 사항을 충족하고 지나치게 복잡하지 않은 적절한 해결책을 만들도록 노력하세요. Vulkan의 사양서는 유용할 수 있지만, 실제로 Vulkan을 어떻게 사용하는지에 대한 최고의 자료는 아닙니다. 대신 여기에 있는 가이드, 하드웨어 모범 사례 가이드, 튜토리얼 및 기타 문서와 같은 외부 소스를 참조하여 보다 심층적인 정보를 얻으세요. 마지막으로, 다양한 솔루션을 프로파일링하는 것은 사용할 해결책 찾는 데 있어 중요한 부분입니다.

커맨드 버퍼 기록(Recording Command Buffers)

초기 Vulkan 튜토리얼과 문서에서는 대부분 커맨드 버퍼를 한 번 쓰고 가능하면 재사용할 것을 권장했습니다. 그러나 재사용함으로써 성능상의 이점을 얻는다고 널리 알려진 것과 달리 실제로 그런 경우는 드물고, 구현의 복잡성 때문에 개발 부담도 커집니다. 직관적이지 않은 것처럼 보일 수 있지만 계산된 데이터를 재사용하는 것이 일반적인 최적화 방법이지만, 오브젝트가 추가 및 제거되는 장면을 관리하고 프레임 단위로 실행되는 드로우 콜을 변화시키는 절두체(프러스텀) 컬링과 같은 기법을 사용하면 커맨드 버퍼 재사용이 심각한 설계 과제가 될 수 있습니다. 따라서 커맨드 버퍼를 관리하고 재녹화가 필요한지 여부를 판단하기 위한 상태를 유지하기 위한 캐싱 체계가 필요합니다. 대신 매 프레임마다 새로운 커맨드 버퍼를 다시 기록하는 것이 좋습니다. 성능이 문제가 되는 경우, 기록을 멀티스레드로 처리하고 포스트 프로세싱과 같이 가변적이지 않은 드로우 콜에 보조 커맨드 버퍼를 사용할 수 있습니다.

다중 파이프라인(Multiple Pipelines)

그래픽스의 VkPipeline 에는 드로우 콜을 수행하는 데 필요한 상태 조합이 포함되어 있습니다. 다양한 쉐이더, 블렌딩 모드, 정점 레이아웃 등으로 장면을 렌더링하려면 각각의 가능성에 대한 파이프라인이 필요합니다. 파이프라인 생성과 드로우 콜 간의 교체에는 비용이 많이 들기 때문에 필요한 경우에만 하는 것이 좋습니다. 그러나 단순한 경우 외에 다양한 기법과 기능을 사용하여 파이프라인 생성이나 교체를 더 줄이는 것은 이점이 보장되지 않은 채 복잡성만 가중되므로 비생산적일 수 있습니다. 대규모 엔진의 경우 이러한 작업이 필요할 수 있지만, 그렇지 않으면 병목 현상이 발생할 가능성은 거의 없습니다. 파이프라인 캐시를 사용하면 더 복잡한 방식에 의존하지 않고도 비용을 더욱 절감할 수 있습니다.

스왑체인 이미지 당 리소스 중복(Resource Duplication per Swapchain Image)

프레임 파이프라인화하는 것은 성능 향상을 위한 일반적인 방법입니다. 여러 프레임을 동시에 렌더링하고 각각 필요한 리소스 복사본을 사용함으로써 리소스 경합을 없애고 지연 시간을 줄입니다. 이를 간단히 구현하면 스왑체인에서 각 이미지에 필요한 리소스가 복제됩니다. 문제는 스왑체인의 각 이미지에 렌더링 리소스를 한 번씩 복제해야 한다고 가정해버리는 것입니다. 각 프레임에 사용되는 커맨드 버퍼 및 세마포어 등 일부 리소스에 대해서는 실용적이지만, 스왑체인 이미지에서 일대일 복제가 필요한 경우는 많지 않습니다. Vulkan은 개발자가 상황에 맞는 복제 수준을 선택할 수 있는 유연성을 제공합니다. 예를 들어 유니폼 버퍼나 프레임당 한 번씩 업데이트되는 데이터처럼 두 개의 사본만 필요한 리소스도 있고, 전혀 중복이 필요하지 않은 리소스도 있습니다.

하나의 큐 패밀리의 다중 큐(Multiple Queues per Queue Family)

몇몇 하드웨어 플랫폼에는 큐 패밀리에 하나 이상의 VkQueue 가 있습니다.이는 별도의 큐에서 동일한 큐 패밀리로 작업을 제출할 수 있다는 점에서 유용할 수 있습니다. 이점이 있을 수 있지만 여분의 큐를 만들거나 사용하는 것이 반드시 더 나은 것은 아닙니다. 구체적인 성능 권장 사항은 하드웨어 제조사의 모범 사례 가이드를 참조하세요.

디스크립터 세트(Descriptor Sets)

디스크립터 세트는 쉐이더에 사용되는 데이터를 용도 및 업데이트 빈도에 따라 쉽게 그룹화할 수 있도록 설계되었습니다. Vulkan 사양에는 하드웨어가 동시에 최소 4개의 디스크립터 세트 사용을 지원하도록 의무화되어 있으며, 대부분의 하드웨어는 최소 8개를 지원합니다. 따라서 합리적이라면 하나 이상의 디스크립터 세트를 사용하지 않을 이유가 거의 없습니다.

올바른 API 사용 사례(Correct API usage practices)

유효성 검사 레이어는 많은 유형의 오류를 잡아낼 수 있지만 완벽하지는 않습니다. 다음은 좋은 습관과 이상한 동작을 만났을 때 생각할 수 있는 오류의 원인을 간단히 정리했습니다.

  • 모든 변수와 구조체를 초기화합니다.

  • 각 구조체에 올바른 sType 을 사용합니다.

  • pNext 체인 사용이 올바른지 확인하고 필요하지 않은 경우 null로 설정합니다.

  • Vulkan에는 기본값이 없습니다.

  • 올바른 열거형, VkFlag, 및 비트마스크 값을 사용합니다.

  • C++의 경우 Vulkan.hpp 와 같은 타입 안전성(type-safe) Vulkan 래퍼를 사용하는 것이 좋습니다.

  • 함수 반환값을 확인합니다.(예: VkResult ).

  • 필요에 따라 적절한 위치에서 정리 함수를 호출합니다.