9.9 KiB
9.9 KiB
🔥 MAJOR REFACTORING GUIDE - 기술 부채 제거 및 코드 간소화
⚠️ CRITICAL: 이 문서는 현재 진행 중인 대규모 리팩토링의 핵심 가이드입니다. AI 토큰 절약 및 작업 연속성을 위해 반드시 읽고 따라야 합니다.
🎯 리팩토링 목표
근본 문제 인식
현재 codebase는 **"방어적 코딩"**으로 증상만 치료하고 있습니다:
- ResourceBarrier NULL 포인터 → NULL 체크 추가 (❌ 증상 치료)
- GPU 리소스 생성 실패 → 더 많은 fallback 로직 (❌ 복잡도 증가)
- 초기화 순서 문제 → 더 많은 상태 체크 (❌ 기술 부채 증가)
해결 철학: "삭제 후 올바른 재설계" (Delete & Redesign Properly)
"잘못된 고성능 구현" < "올바른 설계 기반 구현"
현재 파이프라인 문제점:
- 과도한 추상화: 3단계 복잡한 파이프라인으로 성능 저하
- 잘못된 리소스 관리: NULL placeholder로 인한 크래시 다발
- 역효과적 멀티스레드: 오버헤드 > 실제 성능 향상
- 디버깅 불가능: 복잡한 상태 머신으로 문제 추적 불가
목표:
- 즉시 목표: 안정적인 CPU 기반 재생 (6800 → 800 라인)
- 최종 목표: 올바른 GPU 파이프라인 재설계 (단순하지만 효율적)
📋 단계별 실행 계획
🎯 전체 로드맵
1단계: 잘못된 파이프라인 제거 (현재 진행 중)
- 복잡한 멀티스레드 파이프라인 삭제
- 안정적인 CPU 기반 재생 확보
2단계: 올바른 GPU 파이프라인 재설계 (향후)
// 새로운 단순 설계
CPU Thread: VideoPacket → AV1Decode → YUV Frame
↓ (Zero-copy handoff)
GPU Thread: YUV Frame → D3D12 Upload → YUV→RGB Shader → Screen
3단계: 점진적 최적화 (최종)
- 이중 버퍼링으로 CPU-GPU 병렬화
- 프로파일링 기반 성능 튜닝
🗑️ Phase 1: 잘못된 파이프라인 완전 제거
1.1 제거 대상 파일들 (즉시 삭제)
# Pipeline 디렉토리 전체 제거
rm -rf src/Pipeline/ThreadedDecoder.*
rm -rf src/Pipeline/OverlappedProcessor.*
rm -rf src/Pipeline/DependencyScheduler.*
# 복잡한 GPU 관리 제거
rm -rf src/Rendering/CommandListPool.*
rm -rf src/Rendering/DirectTextureAllocator.*
# 사용하지 않는 유틸리티 제거
rm -rf src/Common/PacketPool.*
rm -rf src/Common/FramePool.*
1.2 VideoPlayerControl.xaml.h 단순화
// 제거할 복잡한 멤버들
❌ std::unique_ptr<::Vav2Player::ThreadedDecoder> m_threadedDecoder;
❌ std::unique_ptr<::Vav2Player::OverlappedProcessor> m_overlappedProcessor;
❌ std::shared_ptr<::Vav2Player::DependencyScheduler> m_dependencyScheduler;
❌ std::shared_ptr<::Vav2Player::FrameDependencyScheduler> m_frameScheduler;
❌ bool m_useMultiThreadedDecoding = true;
❌ bool m_useOverlappedPipeline = true;
❌ bool m_useDependencyScheduling = true;
// 유지할 핵심 멤버들
✅ std::unique_ptr<WebMFileReader> m_fileReader;
✅ std::unique_ptr<IVideoDecoder> m_decoder;
✅ std::unique_ptr<D3D12VideoRenderer> m_d3d12Renderer; // 선택적
1.3 제거할 복잡한 메서드들
// VideoPlayerControl.xaml.cpp에서 완전 삭제
❌ void InitializeThreadedDecoder();
❌ void ShutdownThreadedDecoder();
❌ void InitializeOverlappedProcessor();
❌ void ShutdownOverlappedProcessor();
❌ void InitializeDependencyScheduler();
❌ void ShutdownDependencyScheduler();
❌ void ProcessSingleFrameThreaded();
❌ void ProcessSingleFrameOverlapped();
❌ void ProcessSingleFrameScheduled();
❌ bool SubmitPacketForDecoding();
❌ bool SubmitPacketForOverlappedProcessing();
❌ bool SubmitFrameForScheduledProcessing();
🔧 Phase 2: 단순 처리 경로로 통합
2.1 ProcessSingleFrame() 대폭 단순화
// BEFORE: 1000+ 라인의 복잡한 분기 처리
void ProcessSingleFrame() {
if (m_useDependencyScheduling && m_frameScheduler) {
ProcessSingleFrameScheduled();
} else if (m_useOverlappedPipeline && m_overlappedProcessor) {
ProcessSingleFrameOverlapped();
} else if (m_useMultiThreadedDecoding && m_threadedDecoder) {
ProcessSingleFrameThreaded();
} else {
ProcessSingleFrameLegacy();
}
}
// AFTER: 10라인의 단순 선형 처리
void ProcessSingleFrame() {
VideoPacket packet;
if (!m_fileReader->ReadNextPacket(packet)) return;
VideoFrame frame;
if (!m_decoder->DecodeFrame(packet, frame)) return;
RenderFrameToScreen(frame); // 단일 렌더링 경로
}
2.2 RenderFrameToScreen() 단순화
void RenderFrameToScreen(const VideoFrame& frame) {
// GPU 렌더링 시도 (선택적)
if (m_useHardwareRendering && m_d3d12Renderer && m_d3d12Renderer->IsInitialized()) {
if (m_d3d12Renderer->TryRenderFrame(frame)) {
return; // 성공하면 완료
}
}
// CPU 렌더링 (항상 동작하는 fallback)
RenderFrameSoftware(frame);
}
🧹 Phase 3: 프로젝트 파일 정리
3.1 Vav2Player.vcxproj 정리
<!-- 제거할 파일 참조들 -->
❌ <ClCompile Include="src\Pipeline\ThreadedDecoder.cpp" />
❌ <ClCompile Include="src\Pipeline\OverlappedProcessor.cpp" />
❌ <ClCompile Include="src\Pipeline\DependencyScheduler.cpp" />
❌ <ClCompile Include="src\Rendering\CommandListPool.cpp" />
❌ <ClCompile Include="src\Common\PacketPool.cpp" />
❌ <ClCompile Include="src\Common\FramePool.cpp" />
<!-- 유지할 핵심 파일들 -->
✅ <ClCompile Include="src\FileIO\WebMFileReader.cpp" />
✅ <ClCompile Include="src\Decoder\AV1Decoder.cpp" />
✅ <ClCompile Include="src\Decoder\MediaFoundationAV1Decoder.cpp" />
✅ <ClCompile Include="src\Rendering\D3D12VideoRenderer.cpp" />
🎯 단계별 아키텍처 목표
Phase 1 완료 후: 단순 안정화 아키텍처
VideoPlayerControl
├── WebMFileReader (파일 파싱)
├── IVideoDecoder (AV1 디코딩)
└── SoftwareRenderer (CPU 렌더링, 100% 안정)
Phase 2 목표: 올바른 GPU 파이프라인
VideoPlayerControl
├── WebMFileReader (파일 파싱)
├── IVideoDecoder (AV1 디코딩)
├── GPUTextureUploader (효율적 GPU 업로드)
├── YUVToRGBConverter (GPU 셰이더)
└── D3D12Presenter (화면 출력)
단계별 데이터 플로우
Phase 1: WebM → Packet → Frame → CPU Render → Screen
Phase 2: WebM → Packet → Frame → GPU Pipeline → Screen
↓
(Zero-copy, 단순 병렬)
코드 크기 목표
| 컴포넌트 | 현재 | 목표 | 감소율 |
|---|---|---|---|
| VideoPlayerControl.xaml.cpp | 2500줄 | 400줄 | -84% |
| Pipeline/* | 3000줄 | 0줄 | -100% |
| Rendering/* | 1500줄 | 800줄 | -47% |
| 전체 | 7000줄 | 1200줄 | -83% |
⚠️ 중요한 설계 원칙
1. 단순성 우선 (Simplicity First)
- 복잡한 최적화 < 단순한 동작
- 멀티스레드 < 단일스레드 + 빠른 디코더
- GPU 파이프라인 < CPU 렌더링 + 선택적 GPU
2. 확실성 우선 (Reliability First)
- 100% 동작하는 기본 기능 > 50% 동작하는 고급 기능
- NULL 체크보다 NULL 생성 방지
- 방어 코딩보다 원인 제거
3. 유지보수성 우선 (Maintainability First)
- 선형 처리 경로 > 복잡한 상태 머신
- 명확한 에러 처리 > 복잡한 fallback
- 적은 코드 > 많은 기능
🚨 작업 중 주의사항
절대 하지 말 것
❌ 방어 코딩 추가: NULL 체크, try-catch 남발 ❌ 기능 추가: 새로운 파이프라인이나 최적화 ❌ 점진적 수정: 기존 복잡한 코드를 조금씩 고치기
반드시 할 것
✅ 코드 삭제: 의심스러우면 삭제 ✅ 단순화: 복잡한 분기를 선형 처리로 ✅ 테스트: 각 단계마다 기본 동작 확인
📝 진행 상황 체크리스트
Phase 1: 파이프라인 제거
- ThreadedDecoder.* 삭제
- OverlappedProcessor.* 삭제
- DependencyScheduler.* 삭제
- CommandListPool.* 삭제
- VideoPlayerControl.xaml.h 멤버 정리
- VideoPlayerControl.xaml.cpp 메서드 정리
Phase 2: 로직 단순화
- ProcessSingleFrame() 단순화 (1000줄→10줄)
- RenderFrameToScreen() 단순화
- LoadVideo() 초기화 로직 단순화
- 에러 처리 단순화
Phase 3: 프로젝트 정리
- .vcxproj 파일 정리
- 빌드 테스트
- 기본 동작 테스트 (비디오 재생)
- 코드 라인 수 측정
🔄 중간 중단 시 재시작 가이드
상황 파악 질문
- "현재 어느 Phase까지 완료되었나?"
- "빌드가 성공하는가?"
- "기본 비디오 재생이 동작하는가?"
빠른 재시작 명령어
# 1. 현재 상태 확인
find src/ -name "*.cpp" | grep -E "(Threaded|Overlapped|Dependency)" | wc -l
# 2. 빌드 테스트
cd "D:/Project/video-av1/vav2/Vav2Player/Vav2Player"
MSBuild Vav2Player.vcxproj //p:Configuration=Debug //p:Platform=x64 //v:minimal
# 3. 헤드리스 테스트
cd "x64/Debug/Headless"
./Vav2PlayerHeadless.exe "D:/Project/video-av1/sample/simple_test.webm"
우선순위 복구 순서
- 빌드 수정 (컴파일 에러 해결)
- 기본 동작 복구 (ProcessSingleFrame 단순화)
- 불필요한 코드 삭제 (Phase 1 계속)
💡 성공 지표
정량적 지표
- 전체 코드 라인 수: < 1500줄
- 빌드 시간: < 30초
- 메모리 사용량: < 100MB
- 비디오 재생 성공률: 100%
정성적 지표
- 코드 이해하기 쉬움
- 디버깅 시간 단축
- 새 기능 추가 용이성
- 크래시 발생률 0%
⚡ 핵심 메시지: "삭제가 최고의 디버깅이다"
문서 작성일: 2025-09-21 최종 업데이트: 진행 중