Skip to content

Latest commit

 

History

History
126 lines (103 loc) · 8.47 KB

File metadata and controls

126 lines (103 loc) · 8.47 KB

몽그루 렌더링 성능 기준

최종 갱신: 2026-08-07

이 문서는 탐험과 전투 연출을 바꿀 때 지켜야 할 프레임 예산과 측정 절차를 기록한다. 감각적인 "부드러움"만으로 판단하지 않고, 릴리스와 프로파일 빌드의 프레임 분포로 회귀 여부를 확인한다.

1. 목표 예산

  • 60Hz 기기는 UI와 래스터 작업을 합쳐 프레임당 16.7ms 안에 끝내는 것을 기본으로 한다.
  • 120Hz 기기에서는 8.3ms를 목표로 하되, 고주사율에서 품질을 낮추기보다 먼저 불필요한 빌드·레이아웃·페인트를 제거한다.
  • 핵심 입력과 전투 연출은 평균값만 보지 않는다. p95, p99, 최악 프레임과 20ms·33.4ms 초과 프레임 수를 함께 기록한다.
  • 디버그 빌드는 JIT와 진단 오버헤드가 있으므로 성능 판정에 사용하지 않는다.

2. 탐험 렌더링 계약

애니메이션 경계

  • 배경, 플레이 캐릭터, 수호자, 전투 이펙트, HUD는 각자 필요한 애니메이션만 구독한다. 공통 상위 위젯에서 ambient와 action controller를 합쳐 전체 무대를 매 프레임 다시 빌드하지 않는다.
  • 정적인 원화와 캐릭터는 AnimatedBuilder.childRepaintBoundary 안에 둔다. 타임라인은 위치·투명도만 갱신하고, 캐릭터 스프라이트를 매 틱 새로 구성하지 않는다.
  • 광선, 충돌, 피해 파동처럼 짧고 반복되는 시각 효과는 여러 장식 위젯 대신 한 Canvas 레이어에서 그린다. 이펙트는 서버 판정을 표현할 뿐 피해를 다시 계산하지 않는다.
  • 서버가 확정한 결과는 전투 타임라인이 끝날 때까지 pendingExpedition으로 보관한다. 전투 첫 프레임과 다음 지도·선택지 조립을 겹치지 않고, 결과 화면도 지도와 선택 패널을 한 프레임 간격으로 나눠 반영한다.

이미지 메모리

  • 1600×900 원화를 화면 너비 그대로 디코드하지 않는다. 승인 원본은 보존하고 장소·통합 지형은 960px, 투명 수호자는 768px 모바일 파생본을 빌드한다. 현재 물리 픽셀 너비에 15% 여유를 둔 목표가 파생본 이하일 때만 작은 파일을 선택한다.
  • 선택한 파일에도 ResizeImage를 적용하고, 장면 배경과 이동 카드는 같은 provider와 ImageCache 키를 공유한다. 고밀도 모바일·태블릿·데스크톱은 원본을 유지한다.
  • 현재 장소와 서버가 실제로 열어 준 다음 장소를 합쳐 최대 3장만 선로딩한다. 전체 지역 원화를 한꺼번에 올리면 8장 기준 약 46MB의 RGBA 메모리가 필요하므로 금지한다.
  • 수호자 idle/attack/hit/defeated도 실제 표시 폭에 맞춰 디코드한다. 전투 무대 진입 시 네 상태를 비동기로 준비하되 화면 진입을 이미지 로드 완료까지 막지 않는다.

렌더링 품질

  • 이동과 흔들림은 layout 속성 대신 transform을 사용한다. 투명도 애니메이션은 필요한 작은 레이어에만 적용한다.
  • Android API 29 이상과 iOS의 기본 Impeller 경로를 전제로 한다. 런타임에서 임의의 셰이더 워밍업 우회 코드를 추가하지 않고, 실제 기기의 DevTools shader compilation과 raster 시간을 먼저 확인한다.
  • disableAnimations에서는 ambient controller를 멈추고 최종 판정 상태를 즉시 읽을 수 있어야 한다. 접근성 설정을 성능 옵션처럼 오용하지 않는다.

3. 측정 절차

  1. Flutter 분석, 위젯 테스트, 서버 테스트를 먼저 통과시킨다.
  2. Flutter 도구 명령은 같은 작업 폴더에서 동시에 실행하지 않는다. analyze → test → build 순서로 실행해 산출물 경합을 피한다.
  3. 실제 API와 DB를 연결한 390×844 릴리스 Web에서 평상시 5초와 수호전 스킬 사용 4초를 각각 측정한다.
  4. Chrome Performance 패널 또는 CDP로 일반 CPU, 2배 제한, 4배 제한을 확인한다. FPS, p50, p95, p99, 최대 프레임 간격, 20ms·33.4ms 초과 수를 남긴다. 창이 최소화되거나 가려져 Chrome이 rAF를 1Hz로 제한한 표본은 폐기한다.
  5. Android/iOS 출시 후보는 profile mode의 DevTools Performance view에서 같은 장면을 다시 측정한다. Track widget builds/layouts/paints를 필요한 구간에만 켜고, UI thread와 raster thread 중 어느 쪽이 예산을 넘겼는지 구분한다.
  6. 전투 종료 뒤 다음 장소 카드가 열리는 순간까지 기록한다. 애니메이션 본체가 빨라도 후속 원화 디코드가 긴 프레임을 만들면 실패로 본다.

4. 2026-08-06 전투 기준값

Flutter 3.44 계열 WebAssembly 릴리스, 390×844, 로컬 실제 API 시나리오에서 측정한다. JS heap은 GC 시점에 따라 달라지므로 참고값으로만 쓰고 프레임 분포를 합격 기준으로 삼는다.

조건 구간 FPS p95 p99 최대 20ms 초과 33.4ms 초과
일반 CPU, 변경 전 평상시 5초 60.08 16.8ms - 16.9ms 0 0
일반 CPU, 변경 전 수호전 4초 59.95 16.8ms - 33.5ms 1 1
일반 CPU, 최종 평상시 5초 59.89 16.8ms 16.8ms 16.8ms 0 0
일반 CPU, 최종·콜드 캐시 수호전 4초 59.91 16.8ms 16.8ms 16.8ms 0 0
일반 CPU, 수동 지휘·실제 API 전원 명령+반격 4초 60.10 16.8ms 16.9ms 16.9ms 0 0
일반 CPU, 2026-08-07 Wasm 평상시 호흡·눈깜빡임 3초 60.02 16.8ms - 16.9ms 0 0
일반 CPU, 2026-08-07 Wasm 수동 명령+피격+반격 3초 60.06 16.8ms - 16.8ms 0 0
일반 CPU, 2026-08-07 표준 JS 최종 공격+처치+전환 2.5초 60.13 16.8ms - 16.8ms 0 0
CPU 2배 제한, 최종 수호전 4초 59.79 16.8ms 16.8ms 16.9ms 0 0
CPU 4배 제한, 변경 전 수호전 4초 59.21 16.8ms - 50.0ms 2 2
CPU 4배 제한, 최종 2회 범위 수호전 4초 56.23~58.95 16.8~33.3ms 16.9~33.5ms 66.6~66.7ms 2~13 2~6

일반 CPU와 2배 제한에서는 콜드 장면 디코드, 서버 응답, 전투 종료와 다음 카드 공개를 포함해 20ms 초과 프레임이 없었다. 4배 제한은 결과 패널 조립 구간에서 33.4ms 초과가 남으므로 합격 게이트가 아니라 저사양 회귀 추적값으로 유지한다. 브라우저 측정은 실제 모바일 GPU·열 제한·메모리 압박을 대신하지 않으므로 스토어 배포 전 중급 Android 실기기와 iPhone에서 한 번 더 확인한다.

수동 지휘 실측은 241프레임의 평균 간격 16.639ms였고, 명령 확정에서 combat/turns POST가 한 번만 발생하는 것과 모든 시각 큐가 끝난 뒤 서버 결과가 반영되는 것을 같이 확인했다.

2026-08-07 회귀에서는 Wasm과 표준 JS 릴리스를 같은 390×844 시나리오로 확인했다. 최종 처치 상태는 1,100ms 동안 유지되며, 1,800ms 캡처까지 쓰러진 수호자와 승리 문구가 남고 2,000ms 캡처에서 결과 화면으로 전환됐다. 로컬 Windows의 애플리케이션 제어 정책이 wasm-opt.exe를 차단하는 환경에서는 정책을 우회하지 않고 표준 JS 릴리스를 검증한다. Wasm 출시 후보는 허용된 CI 또는 빌드 머신에서 동일 테스트를 다시 수행한다.

5. 변경 시 체크리스트

  • 상위 AnimatedBuilderPlantView, 배경 원화, 전체 HUD를 다시 빌드하지 않는가
  • 새 이미지가 화면 물리 크기보다 훨씬 크게 디코드되지 않는가
  • 화면에 도달할 수 없는 장면까지 선로딩하지 않는가
  • Opacity, blur, clip, saveLayer가 전체 화면 크기로 확장되지 않는가
  • 전투 시작, 수호자 자세 전환, 피해 숫자 표시, 전투 종료, 다음 장소 공개에 긴 프레임이 없는가
  • reduced motion, 200% 글자, 320px 화면에서 동작과 레이아웃 계약을 함께 지키는가

6. 기준 자료