Files
video-v1/vav2/docs/completed/optimization/MAJOR_REFACTORING_GUIDE.md
2025-09-28 17:10:41 +09:00

9.9 KiB

🔥 MAJOR REFACTORING GUIDE - 기술 부채 제거 및 코드 간소화

⚠️ CRITICAL: 이 문서는 현재 진행 중인 대규모 리팩토링의 핵심 가이드입니다. AI 토큰 절약 및 작업 연속성을 위해 반드시 읽고 따라야 합니다.


🎯 리팩토링 목표

근본 문제 인식

현재 codebase는 **"방어적 코딩"**으로 증상만 치료하고 있습니다:

  • ResourceBarrier NULL 포인터 → NULL 체크 추가 ( 증상 치료)
  • GPU 리소스 생성 실패 → 더 많은 fallback 로직 ( 복잡도 증가)
  • 초기화 순서 문제 → 더 많은 상태 체크 ( 기술 부채 증가)

해결 철학: "삭제 후 올바른 재설계" (Delete & Redesign Properly)

"잘못된 고성능 구현" < "올바른 설계 기반 구현"

현재 파이프라인 문제점:

  • 과도한 추상화: 3단계 복잡한 파이프라인으로 성능 저하
  • 잘못된 리소스 관리: NULL placeholder로 인한 크래시 다발
  • 역효과적 멀티스레드: 오버헤드 > 실제 성능 향상
  • 디버깅 불가능: 복잡한 상태 머신으로 문제 추적 불가

목표:

  1. 즉시 목표: 안정적인 CPU 기반 재생 (6800 → 800 라인)
  2. 최종 목표: 올바른 GPU 파이프라인 재설계 (단순하지만 효율적)

📋 단계별 실행 계획

🎯 전체 로드맵

1단계: 잘못된 파이프라인 제거 (현재 진행 중)

  • 복잡한 멀티스레드 파이프라인 삭제
  • 안정적인 CPU 기반 재생 확보

2단계: 올바른 GPU 파이프라인 재설계 (향후)

// 새로운 단순 설계
CPU Thread: VideoPacket  AV1Decode  YUV Frame
     (Zero-copy handoff)
GPU Thread: YUV Frame  D3D12 Upload  YUVRGB 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 파일 정리
  • 빌드 테스트
  • 기본 동작 테스트 (비디오 재생)
  • 코드 라인 수 측정

🔄 중간 중단 시 재시작 가이드

상황 파악 질문

  1. "현재 어느 Phase까지 완료되었나?"
  2. "빌드가 성공하는가?"
  3. "기본 비디오 재생이 동작하는가?"

빠른 재시작 명령어

# 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"

우선순위 복구 순서

  1. 빌드 수정 (컴파일 에러 해결)
  2. 기본 동작 복구 (ProcessSingleFrame 단순화)
  3. 불필요한 코드 삭제 (Phase 1 계속)

💡 성공 지표

정량적 지표

  • 전체 코드 라인 수: < 1500줄
  • 빌드 시간: < 30초
  • 메모리 사용량: < 100MB
  • 비디오 재생 성공률: 100%

정성적 지표

  • 코드 이해하기 쉬움
  • 디버깅 시간 단축
  • 새 기능 추가 용이성
  • 크래시 발생률 0%

핵심 메시지: "삭제가 최고의 디버깅이다"

문서 작성일: 2025-09-21 최종 업데이트: 진행 중