14 KiB
14 KiB
Godot Demo vs Vav2Player 성능 차이 분석 및 최적화 방안
📊 현재 상황 분석
Vav2Player (WinUI3) CPU 파이프라인
- 성능: 상당히 빠른 CPU 렌더링 성능 달성
- GPU 가속: D3D12VideoRenderer로 GPU YUV→RGB 변환 (15-30배 성능 향상)
- 메모리 최적화: FramePool, 텍스처 캐싱 완전 구현
Godot Demo CPU 파이프라인
- 현재 상태: CPU 파이프라인으로 렌더링 중
- 성능 이슈: Vav2Player 대비 상대적으로 느린 처리 속도
- 최적화 여지: 여러 성능 병목점 발견
🔍 성능 차이 원인 분석
1. 메모리 복사 오버헤드
// Godot Demo - CreateSingleBlockYUVTexture() 분석
// ✅ 이미 단일 블록 복사로 최적화됨
Buffer.MemoryCopy(srcPtr, dstPtr, totalSize, totalSize); // 1회 복사
현재 상태: ✅ 이미 최적화됨 (3번 복사 → 1번 복사)
2. Godot 특유의 성능 병목점
A. ImageTexture 생성/업데이트 패턴
// 현재 구현
var yuvImage = Image.CreateFromData((int)totalSize, 1, false, Image.Format.R8, yuvData);
if (_material.GetShaderParameter("yuv_texture").AsGodotObject() == null)
{
yuvTexture = ImageTexture.CreateFromImage(yuvImage); // 새 생성
}
else
{
yuvTexture.Update(yuvImage); // 기존 업데이트
}
병목점:
Image.CreateFromData()매번 호출- Godot 내부 메모리 관리 오버헤드
- C# → Godot 네이티브 경계 전환 비용
B. 셰이더 파라미터 설정 오버헤드
// 매 프레임마다 실행
_material.SetShaderParameter("yuv_texture", yuvTexture);
_material.SetShaderParameter("y_offset", 0);
_material.SetShaderParameter("u_offset", (int)ySize);
_material.SetShaderParameter("v_offset", (int)(ySize + uSize));
_material.SetShaderParameter("y_size", (int)ySize);
_material.SetShaderParameter("u_size", (int)uSize);
_material.SetShaderParameter("frame_width", frame.width);
_material.SetShaderParameter("frame_height", frame.height);
병목점: 매 프레임마다 8개 파라미터 설정
C. Timer 기반 재생 vs 직접 루프
// 현재: Timer 기반 (33.33ms 간격)
private Timer _playbackTimer;
private double _targetFrameRate = 30.0;
병목점: Timer 정확도 및 스케줄링 오버헤드
3. Vav2Player vs Godot 아키텍처 차이
| 항목 | Vav2Player (현재) | Godot Demo (현재) |
|---|---|---|
| 렌더링 | 직접 D3D12 | Godot 렌더링 엔진 경유 |
| 메모리 관리 | 네이티브 C++ | C# + Godot 관리 메모리 |
| 텍스처 업로드 | 직접 GPU 메모리 | Godot 텍스처 시스템 |
| 스레딩 | 단순화된 GPU 스레드 | Godot 메인 스레드만 |
| 코드 복잡도 | ✅ 단순 (800줄) | 🔶 중간 |
| 멀티스레드 이력 | 🔄 복잡한 시스템에서 단순화 | ❌ 멀티스레드 미적용 |
3.1 Vav2Player 멀티스레딩 진화 과정
과거 (복잡한 멀티스레드 시스템):
ThreadedDecoder,OverlappedProcessor,DependencyScheduler등 복잡한 멀티스레드 컴포넌트들- 6800줄의 복잡한 파이프라인 코드
- Producer-Consumer 패턴, 복잡한 스레드 동기화
현재 (단순화된 시스템):
- 88% 코드 감소 (6800줄 → 800줄)
- 복잡한 멀티스레드 파이프라인 제거됨
- 단순 GPU 파이프라인: CPU Thread → GPU Thread만 유지
ProcessSingleFrame()1000줄 → 25줄로 대폭 단순화
3.2 멀티스레딩 최적화 잠재력
| 플랫폼 | 현재 상태 | Phase 2 멀티스레딩 효과 |
|---|---|---|
| Vav2Player | 🔶 기본 GPU 스레드 존재 | 🔧 기존 시스템 확장 (추가 향상 제한적) |
| Godot Demo | ❌ 모든 처리가 메인 스레드 | ⚡ 새로운 멀티스레드 도입 (대폭 향상 기대) |
결론: Phase 2 멀티스레딩은 Godot Demo에서 훨씬 큰 성능 향상을 가져올 것으로 예상됨
🚀 최적화 방안 및 개선 아이디어
Phase 1: 즉시 적용 가능한 최적화
1.1 Image 재사용 최적화
// 개선안: Image 객체 재사용
private Image _cachedYUVImage;
private byte[] _cachedYUVData;
private bool CreateSingleBlockYUVTextureOptimized(VavCoreVideoFrame frame)
{
// 기존 버퍼 재사용
if (_cachedYUVData == null || _cachedYUVData.Length != totalSize)
{
_cachedYUVData = new byte[totalSize];
_cachedYUVImage = Image.Create((int)totalSize, 1, false, Image.Format.R8);
}
// 메모리 복사
unsafe
{
fixed (byte* dstPtr = _cachedYUVData)
{
Buffer.MemoryCopy(srcPtr, dstPtr, totalSize, totalSize);
}
}
// Image 데이터 직접 업데이트 (CreateFromData 호출 제거)
_cachedYUVImage.SetData(_cachedYUVData);
// 텍스처 업데이트
if (_cachedTexture == null)
{
_cachedTexture = ImageTexture.CreateFromImage(_cachedYUVImage);
}
else
{
_cachedTexture.Update(_cachedYUVImage);
}
}
1.2 셰이더 파라미터 캐싱
// 개선안: 변경된 파라미터만 업데이트
private struct CachedShaderParams
{
public int width, height;
public int y_size, u_size, v_size;
}
private CachedShaderParams _lastParams;
private void UpdateShaderParametersIfChanged(VavCoreVideoFrame frame)
{
var currentParams = new CachedShaderParams
{
width = frame.width,
height = frame.height,
y_size = frame.width * frame.height,
u_size = (frame.width / 2) * (frame.height / 2),
v_size = (frame.width / 2) * (frame.height / 2)
};
if (!currentParams.Equals(_lastParams))
{
// 변경된 경우만 업데이트
_material.SetShaderParameter("frame_width", currentParams.width);
_material.SetShaderParameter("frame_height", currentParams.height);
_material.SetShaderParameter("y_size", currentParams.y_size);
_material.SetShaderParameter("u_size", currentParams.u_size);
_material.SetShaderParameter("v_size", currentParams.v_size);
_lastParams = currentParams;
}
// 텍스처만 매번 업데이트
_material.SetShaderParameter("yuv_texture", yuvTexture);
}
1.3 프레임 스킵 및 적응형 품질
// 개선안: 성능 기반 적응형 품질 조정
private class PerformanceMonitor
{
private Queue<double> _frameTimes = new Queue<double>();
private const int SAMPLE_SIZE = 30;
public bool ShouldSkipFrame()
{
if (_frameTimes.Count >= SAMPLE_SIZE)
{
double avgTime = _frameTimes.Average();
return avgTime > 33.33; // 30fps 기준
}
return false;
}
}
Phase 2: 아키텍처 레벨 최적화
2.1 RenderingDevice 직접 활용
// Zero-Copy GPU Pipeline 구현
private bool TryGPUSurfaceRendering(VavCoreVideoFrame frame)
{
var renderingServer = RenderingServer.Singleton;
var device = renderingServer.GetRenderingDevice();
if (device != null)
{
// GPU Surface 직접 바인딩 (Vav2Player 방식과 유사)
return UpdateGPUSurfaceTextures(frame, device);
}
return false; // CPU fallback
}
2.2 멀티스레딩 디코딩 (Godot Demo 전용 최적화)
주요 타겟: Godot Demo (현재 모든 처리가 메인 스레드)
Vav2Player: 이미 단순화된 GPU 스레드 존재 - 추가 효과 제한적
// 별도 스레드에서 디코딩 수행 (Godot Demo 메인 스레드 부하 해결)
private class AsyncDecoder
{
private Thread _decodingThread;
private ConcurrentQueue<VavCoreVideoFrame> _frameQueue;
public void StartAsyncDecoding()
{
_decodingThread = new Thread(DecodingLoop);
_decodingThread.Start();
}
private void DecodingLoop()
{
while (_isRunning)
{
// 별도 스레드에서 디코딩
var frame = DecodeNextFrame();
_frameQueue.Enqueue(frame);
}
}
}
Phase 3: Godot Engine 수준 최적화
3.1 커스텀 렌더링 플러그인
# Godot GDExtension으로 네이티브 렌더링 구현
# C++로 직접 Vulkan/D3D12 접근
3.2 메모리 풀링 시스템
// Godot 네이티브 메모리 풀 활용
private class GodotMemoryPool
{
private List<ImageTexture> _texturePool;
private List<Image> _imagePool;
public ImageTexture GetPooledTexture()
{
// 재사용 가능한 텍스처 반환
}
}
📈 예상 성능 향상
Phase 1 최적화 (즉시 적용 가능)
- Image 재사용: 20-30% 성능 향상
- 셰이더 파라미터 캐싱: 10-15% 성능 향상
- 프레임 스킵: 안정적인 30fps 유지
Phase 2 최적화 (중기) - 플랫폼별 차등 효과
Godot Demo (주요 혜택)
- RenderingDevice 직접 활용: 50-70% 성능 향상 (GPU 가속 적용 시)
- 멀티스레딩: 60-80% 성능 향상 (현재 메인 스레드만 사용)
- UI 반응성: 메인 스레드 블로킹 해결로 극적 개선
Vav2Player (제한적 추가 효과)
- 추가 GPU 스레드: 10-20% 성능 향상 (이미 기본 GPU 스레드 존재)
- 정교한 멀티스레딩: 15-25% 성능 향상 (기존 단순화 시스템 확장)
Phase 3 최적화 (장기)
- 커스텀 렌더링 플러그인: Vav2Player 수준의 성능 달성 가능
- 네이티브 메모리 관리: 추가 10-20% 성능 향상
🎯 우선순위별 구현 계획
1순위: 즉시 적용 (1-2일)
- Image 객체 재사용 최적화
- 셰이더 파라미터 캐싱
- 성능 모니터링 추가
2순위: 단기 (1주)
- 프레임 스킵 로직 구현
- 적응형 품질 조정
- 비동기 디코딩 스레드
3순위: 중기 (2-3주)
- RenderingDevice 직접 활용
- Zero-Copy GPU Pipeline 구현
- 멀티스레딩 아키텍처
4순위: 장기 (1개월+)
- Godot GDExtension 플러그인
- 네이티브 렌더링 파이프라인
- 커스텀 메모리 풀링
🔧 구현 시 주의사항
Godot 특수성 고려
- C# → Godot 경계: 과도한 호출 최소화
- 메모리 관리: Godot GC와 .NET GC 이중 관리
- 스레드 안전성: Godot 메인 스레드 제약
호환성 유지
- 기존 API 유지: 인터페이스 변경 최소화
- 플랫폼 독립성: Windows 외 플랫폼 고려
- Godot 버전 호환: 4.4.1+ 지원
📊 성능 측정 계획
측정 지표
- 프레임 처리 시간: 디코딩 → 렌더링 전체 시간
- 메모리 사용량: Godot 관리 + .NET 관리 메모리
- GPU 사용률: GPU 가속 적용 시
- CPU 사용률: 멀티스레딩 효과 측정
벤치마크 환경
- 해상도: 320×240, 1920×1080, 3840×2160
- 프레임레이트: 30fps, 60fps
- 파일 형식: WebM/AV1 다양한 비트레이트
결론:
-
Godot Demo의 성능 병목점은 주로 Godot 엔진의 오버헤드와 C# 바인딩 비용에서 발생하며, 특히 메인 스레드에서 모든 처리가 진행되는 점이 가장 큰 제약입니다.
-
Vav2Player는 이미 복잡한 멀티스레드 시스템을 거쳐 단순화된 상태로, 추가 최적화 여지가 제한적입니다.
-
Phase 2 멀티스레딩은 Godot Demo에서 극적인 성능 향상을 가져올 것으로 예상되며, 이는 Vav2Player에서 이미 경험한 멀티스레드의 혜택을 Godot 환경에서도 구현하는 것입니다.
-
실용적인 성능 달성: Godot Demo는 Phase 1-2 최적화만으로도 상당한 성능 향상이 가능하며, Phase 3의 네이티브 플러그인 없이도 실용적인 수준에 도달할 수 있을 것으로 판단됩니다.
🎉 Godot VavCore 데모 성공적 실행 완료 (2025-09-28)
실제 실행 결과
VavCore Demo: Initializing...
✅ VavCore Extension loaded successfully!
✅ Video loaded successfully! (test_video.webm - 3840x2160)
✅ Multithreaded playback started
✅ GPU YUV textures created successfully (3-block method)
✅ Frame processing: 9-15ms per frame
✅ Video displays at (1152, 551) in AspectFit mode
달성한 성과
- 완전한 VavCore 통합: DLL 로딩, 플레이어 생성, 비디오 재생 모든 단계 성공
- 4K 비디오 재생: 3840x2160 해상도 AV1 비디오 정상 재생 확인
- 멀티스레드 디코딩: 백그라운드 디코딩 스레드와 GPU 렌더링 스레드 분리 작동
- GPU YUV 렌더링: 3개 블록 방식으로 Y/U/V 텍스처 생성 및 셰이더 변환
- 실시간 성능: 10-11ms 평균 처리 시간으로 안정적인 재생 성능
Phase 1 최적화 구현 검증
- ✅ 3-블록 텍스처 효율성: CreateFromImage → Update 방식으로 텍스처 재사용
- ✅ 메모리 복사 최적화: stride == width 조건에서 full block copy 적용
- ✅ 프레임 큐잉: 5개 프레임 버퍼링으로 부드러운 재생
- ✅ AspectFit 렌더링: 3840x2160 → 1152x551 비율 유지 정확한 표시
성능 분석 결과
| 항목 | 실제 측정값 | 분석 |
|---|---|---|
| 프레임 처리 시간 | 9.36-15.68ms | 4K 기준 우수한 성능 |
| 텍스처 업데이트 | Image.Update 방식 | 메모리 재할당 없이 효율적 |
| 메모리 복사 | Full block copy | Stride 최적화 적용됨 |
| GPU 가속 | YUV→RGB 셰이더 | 하드웨어 가속 정상 작동 |
| 버퍼링 | 5프레임 큐 | 안정적인 스트리밍 |
아키텍처 검증
✅ VavCore.dll (C API)
↓ P/Invoke
✅ VavCore.Wrapper (C#)
↓ Godot Extension
✅ VavCorePlayer (Godot C#)
↓ GPU Pipeline
✅ YUV Shader → RGB Display
다음 단계 최적화 계획
- Phase 2 멀티스레딩: CPU 디코딩과 GPU 렌더링 완전 분리
- Memory Pool: VideoFrame 재사용으로 메모리 할당 오버헤드 제거
- Shader Parameter 캐싱: 변경된 파라미터만 업데이트
- Adaptive Quality: 실시간 성능 기반 해상도 조정
생성일: 2025-09-28 분석 대상: Godot Demo vs Vav2Player 성능 비교 실행 완료일: 2025-09-28