Move old notes

This commit is contained in:
2025-10-12 02:04:54 +09:00
parent 54c1516205
commit b9b65a3571
34 changed files with 132 additions and 0 deletions

132
vav2/notes/av1-dpb.txt Normal file
View File

@@ -0,0 +1,132 @@
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ > NVDEC API 에 관해서 질문이 있다. 각 프레임을 디코딩해서 Video Frame 으로 얻어 와서 cuvidMapVideoFrame() 를 통해서 실제 │
│ frame data 를 얻어온다. │
│ 그런데 AV1 디코딩은 최대 16개 이상의 프레임을 보관했다가, frame reordering 에 의해서 이전에 디코딩했던 프레임을 화면에 │
│ 렌더링할 경우가 있다. NVDEC 에서 video frame 에 대해서 캐싱을 지원하고 있는지 궁금하다. 현재까지의 실험으로는 캐싱을 하지 │
│ 않는 것으로 밝혀졌는데, 사실인지 검증이 필요하다. 필요하면 웹서칭을 통해서 사실 검증을 진행해도 좋다. │
│ 만약, video frame 캐싱을 지원하지 않는다면 NVDEC API 로 비디오 렌더링을 구현할 때 사용자가 직접 16개의 프레임을 직접 │
│ 캐싱해서 보관해야 하는지 궁금하고, D3D12 texture 에 렌더링까지 해서 캐싱하는 것이 유리할지 (메모리나 연산 측면에서), │
│ 아니면 CUDA video frame 으로 캐싱을 가지고 있다가, 나중에 D3D12 texture 로 렌더링할 때 그 때 데이터 변환을 수행하는 것이 │
│ 좋은지도 궁금하다. │
│ 결론으로 AV1 frame format 의 순서와 렌더링 순서는 서로 뒤바뀌는 현상이 있어서 16개의 frame 정도는 캐싱할 필요가 있는데, │
│ NVDEC CUDA layer 에서 이를 지원해주는지, 지원해주지 않는다면 application 에서 어떻게 캐싱을 구현하는 것이 좋은지 │
│ 메모리/연산 측면에서 효율적인 방안에 대해서 검토를 부탁한다. │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ 훌륭한 질문입니다. AV1 디코딩과 NVDEC API의 동작 방식, 그리고 애플리케이션 레벨에서의 효율적인 렌더링 전략에 대한 핵심적인
내용이 모두 포함되어 있습니다. 질문을 세 부분으로 나누어 상세히 답변해 드리겠습니다.
1. NVDEC API는 프레임 캐싱/재정렬을 지원하는가?
- NVDEC의 역할: NVDEC는 저수준(low-level) 하드웨어 가속 디코더입니다. 주된 역할은 압축된 비디오 비트스트림(AV1, HEVC 등)을
입력받아 디코딩된 원본 비디오 프레임(YUV 포맷)을 최대한 빨리 GPU 메모리에 출력하는 것입니다. 즉, 디코딩 순서(Decode
Order)대로 동작합니다.
따라서 AV1처럼 프레임 재정렬이 필수적인 코덱을 사용하려면, 사용자가 말씀하신 대로 애플리케이션에서 직접 최대 16개(또는 그
이상)의 프레임을 보관할 캐시(버퍼)를 구현해야 합니다.
---
2. 프레임 캐싱 구현 방안: CUDA Frame vs D3D12 Texture
방안 A: CUDA 비디오 프레임(CUvideoptr)으로 캐싱
- 동작 방식:
- 장점:
- 단점:
- 동작 방식:
- 단점:
압도적으로 `방안 A`, 즉 CUDA 비디오 프레임 형태로 캐싱하는 것을 권장합니다.
현대적인 고성능 비디오 플레이어는 모두 이 방식을 사용합니다. 이유는 다음과 같습니다.
1. 메모리가 핵심입니다: 비디오 재생, 특히 4K/8K 고해상도 비디오에서 가장 큰 병목은 VRAM입니다. CUDA 프레임(NV12)으로 캐싱하는
것은 D3D12 RGB 텍스처로 캐싱하는 것에 비해 VRAM을 절반 이하로 사용하므로, 더 높은 해상도와 더 많은 캐시 프레임을
안정적으로 유지할 수 있습니다.
- NVDEC는 프레임 재정렬을 해주지 않으므로, 애플리케이션에서 직접 프레임 캐시(DPB)를 구현해야 합니다.
╭──────────────╮
│ > continue │
╰──────────────╯
✦ 알겠습니다. 이어서 NVDEC와 D3D12를 사용한 고성능 비디오 렌더링 파이프라인을 구축할 때 고려해야 할 추가적인 기술적 세부사항과
구현 팁에 대해 설명하겠습니다.
4. 애플리케이션 DPB(Decoded Picture Buffer) 구현 전략
CUDA 프레임 인덱스를 캐싱하기로 결정했으니, 이제 이 DPB를 어떻게 효율적으로 관리할지에 대한 구체적인 전략이 필요합니다.
- 자료구조 선택:
- 버퍼 관리 로직:
5. CUDA-D3D12 Interoperability 심화
1. 외부 메모리 할당: cuvidCtxLock으로 컨텍스트를 잠근 후, cuMemCreate를 사용하여 외부 메모리 핸들(External Memory Handle)을
생성할 D3D12 리소스(ID3D12Resource)를 준비합니다. 이 리소스는 디코더의 출력 포맷(예: DXGI_FORMAT_NV12)과 일치해야 합니다.
이 방식은 NVDEC가 직접 D3D12 리소스에 디코딩 결과를 쓰는 가장 효율적인 경로입니다. cuvidMapVideoFrame을 사용하는 것보다 한
단계 더 최적화된 방법이라고 할 수 있습니다.
### 6. 동기화 문제 (Synchronization)
CUDA와 D3D12는 서로 다른 비동기식 커맨드 큐를 사용하므로, 둘 사이의 작업 순서를 보장하기 위한 명시적인 동기화가 필수적입니다.
- `cudaExternalSemaphore` 사용:
이러한 동기화는 파이프라인의 안정성을 보장하고, 리소스 접근 충돌로 인한 크래시나 깨진 화면을 방지하는 데 매우 중요합니다.
### 최종 요약 및 제언
- DPB 관리: PTS를 키로 사용하는 맵을 구현하고, pfnDisplayPicture 콜백을 통해 표시할 프레임을 식별하며, 더 이상 필요 없는
프레임은 즉시 해제하여 디코더 버퍼 고갈을 방지하세요.
이러한 개념들을 VavCore 프로젝트에 적용한다면, CPU 부하를 최소화하면서 매우 높은 성능을 내는 하드웨어 가속 비디오 플레이어를
구현할 수 있을 것입니다. 현재 VavCore의 아키텍처는 이러한 저수준 최적화를 적용하기에 매우 적합한 구조로 보입니다.
╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ > NVDEC API 에 관해서 질문이 있다. 각 프레임을 디코딩해서 Video Frame 으로 얻어 와서 cuvidMapVideoFrame() 를 통해서 실제 │
│ frame data 를 얻어온다. │
│ 그런데 AV1 디코딩은 최대 16개 이상의 프레임을 보관했다가, frame reordering 에 의해서 이전에 디코딩했던 프레임을 화면에 │
│ 렌더링할 경우가 있다. NVDEC 에서 video frame 에 대해서 캐싱을 지원하고 있는지 궁금하다. 현재까지의 실험으로는 캐싱을 하지 │
│ 않는 것으로 밝혀졌는데, 사실인지 검증이 필요하다. 필요하면 웹서칭을 통해서 사실 검증을 진행해도 좋다. │
│ 만약, video frame 캐싱을 지원하지 않는다면 NVDEC API 로 비디오 렌더링을 구현할 때 사용자가 직접 16개의 프레임을 직접 │
│ 캐싱해서 보관해야 하는지 궁금하고, D3D12 texture 에 렌더링까지 해서 캐싱하는 것이 유리할지 (메모리나 연산 측면에서), │
│ 아니면 CUDA video frame 으로 캐싱을 가지고 있다가, 나중에 D3D12 texture 로 렌더링할 때 그 때 데이터 변환을 수행하는 것이 │
│ 좋은지도 궁금하다. │
│ 결론으로 AV1 frame format 의 순서와 렌더링 순서는 서로 뒤바뀌는 현상이 있어서 16개의 frame 정도는 캐싱할 필요가 있는데, │
│ NVDEC CUDA layer 에서 이를 지원해주는지, 지원해주지 않는다면 application 에서 어떻게 캐싱을 구현하는 것이 좋은지 │
│ 메모리/연산 측면에서 효율적인 방안에 대해서 검토를 부탁한다. │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ 네, 다시 한번 질문의 핵심을 요약하고 명확히 답변해 드리겠습니다. 이전에 답변 드린 내용의 핵심을 정리하는 방식으로
설명하겠습니다.
### 질문 요약
1. NVDEC의 자동 캐싱/재정렬 지원 여부: AV1의 프레임 재정렬에 필요한 캐싱(버퍼링)을 NVDEC가 자동으로 처리해주는가?
1. NVDEC의 자동 캐싱 지원 여부: 지원하지 않음
- 사용자의 실험 결과가 정확합니다. NVDEC는 디코딩 순서(Decode Order)에 따라 비디오 프레임을 생성할 뿐, 표시
순서(Presentation Order)에 맞춰 프레임을 캐싱하거나 재정렬하는 기능은 제공하지 않습니다.
메모리와 연산 효율성을 종합적으로 고려했을 때, 디코딩된 CUDA 비디오 프레임(`CUvideoptr` 또는 관련 인덱스) 형태로 캐싱하는
것이 압도적으로 유리합니다.
| 항목 | 방안 A: CUDA 프레임으로 캐싱 (권장) | 방안 B: D3D12 텍스처로 캐싱 |
| :--- | :--- | :--- |
| 메모리 효율성 | 매우 높음. YUV(NV12 등) 포맷으로 저장하여 VRAM 사용량 최소화. (RGB 대비 1/2 ~ 1/3 수준) | 매우 낮음. 비압축
RGB 포맷으로 저장하여 VRAM 사용량 극대화. 고해상도에서 치명적. |
| 렌더링 시 연산 | YUV->RGB 색상 변환 셰이더 실행 필요. (현대 GPU에서 부담이 거의 없는 저비용 연산) | 이미 변환된 텍스처를
복사(Blit)만 하면 됨. (연산 비용 가장 낮음) |
| 구현 복잡도 | 렌더링 시 색상 변환 로직이 추가되나, 표준적인 방식. | 렌더링 로직은 단순해지나, 디코딩 직후 변환 과정이
추가됨. |
| 유연성 | 렌더링 시점에 색 공간, 톤 매핑 등을 유연하게 변경 가능. | 모든 효과가 미리 적용된 상태로 '구워져' 유연성 낮음. |
### 최종 결론
AV1의 프레임 재정렬 문제를 해결하기 위해 애플리케이션에서 직접 프레임 버퍼를 구현해야 하며, VRAM을 효율적으로 사용하기 위해
디코딩된 프레임을 원본 YUV 포맷(CUDA 프레임) 그대로 버퍼에 저장하고, 실제 화면에 렌더링하는 시점에 셰이더를 통해 실시간으로
YUV->RGB 색상 변환을 수행하는 것이 최적의 방안입니다.
이 방식은 현대적인 고성능 비디오 플레이어의 표준적인 아키텍처입니다.