⚡ Electron7. 성능 & 메모리05 · GPU & Rendering — 가속이 항상 정답은 아니다

05 · GPU & Rendering — 가속이 항상 정답은 아니다

질문: “하드웨어 가속을 켜면 항상 빠르다” — 맞는 말인가? 한 줄 답: 대부분 환경에선 맞다. 그러나 가상 머신·원격 데스크톱·구형 GPU 드라이버·일부 Linux 환경에서는 오히려 느리거나 화면이 깜빡인다 — 그래서 app.disableHardwareAcceleration()전략적으로 켜는 카드가 된다.


Pyramid Top

Chromium은 Skia로 그리고, compositorGPU 프로세스를 통해 화면에 합성한다. 이게 대부분 잘 작동하지만 — 모든 그래픽 스택이 동일하지 않다. 가상 머신의 가상 GPU, 원격 데스크톱의 VNC/RDP 가상 화면, 회사 VDI의 소프트웨어 렌더링, 일부 Linux Intel HD 드라이버 — 이런 환경에선 가속이 오버헤드다.

이 문서는 가속을 언제 끄나의 결정과, 켰을 때 화면이 느려 보이는 패턴(paint storm)을 가른다.


사고 흐름


Why — Chromium 렌더 파이프라인의 단계

단계어디서 (프로세스)무엇GPU 영향
LayoutRenderer (CPU)DOM + CSS → 박스 위치영향 없음
PaintRenderer (CPU/Skia)픽셀 → display listSkia는 GPU backend 가능
CompositeGPU process레이어 합성 → 프레임버퍼GPU 가속 핵심
DisplayOS compositor모니터로 출력OS가 책임

“GPU 가속”의 정확한 의미: ① Skia paint를 GPU에서 / ② compositor를 GPU에서. 둘 다 각각 끌 수 있다 (--disable-gpu-rasterization, --disable-gpu-compositing).


How — disableHardwareAcceleration()

// main.js — app.whenReady() *전에* 호출해야 함
const { app } = require('electron');
 
if (shouldDisableGpu()) {
  app.disableHardwareAcceleration();
}
 
function shouldDisableGpu() {
  // 예: 환경변수로 사용자 선택
  if (process.env.DISABLE_GPU === '1') return true;
 
  // 예: 알려진 문제 환경 감지
  if (process.platform === 'linux' && isVirtualGpu()) return true;
 
  return false;
}

효과:

  • GPU process가 여전히 띄움 (compositing은 SW로) → 메모리는 거의 절약 안 됨.
  • animation, scroll, video가 느려질 수 있음.
  • 그러나 깜빡임/freeze가 사라지면 사용자 체감은 빨라짐.

언제 켜나 (off로):

환경
VMware/Parallels VM가상 GPU가 CPU 에뮬 → 느림
원격 데스크톱 (RDP, VNC)변경된 픽셀만 전송하는 게 가속 OFF가 더 좋음
회사 VDI (Citrix, Horizon)같은 이유
일부 Linux Intel/AMD 드라이버깜빡임/tearing 발생
검은 화면 / 흰 화면 버그거의 항상 GPU 가속이 원인 (Linux)

VS Code 사례: Linux에서 검은 화면 버그가 다년간 issue tracker의 상위. 해법은 거의 항상 환경변수로 가속 끄기.


How — 진단 도구

chrome://gpu (Renderer에서)

// Renderer DevTools에서 직접 입력
// 또는 BrowserWindow로 한 번 띄우기
const w = new BrowserWindow({ /* ... */ });
w.loadURL('chrome://gpu');

다음을 보여준다:

  • Graphics Feature Status: Canvas / Compositing / WebGL / Video Decode 각각 Hardware accelerated인지 Software only인지.
  • Driver Bug Workarounds: Chromium이 이미 우회 패치를 적용한 항목.
  • GPU process가 살아 있는가 (간헐 crash 추적).

app.getGPUFeatureStatus()

console.log(app.getGPUFeatureStatus());
// {
//   "2d_canvas": "enabled",
//   "gpu_compositing": "enabled",
//   "rasterization": "enabled",
//   "video_decode": "enabled",
//   ...
// }

FPS / Paint flashing

DevTools → Rendering 패널 →

  • Paint flashing: 매 프레임 어디가 다시 그려지는지 녹색으로 깜빡임. 전체 화면이 깜빡이면 paint storm.
  • Frame Rendering Stats: 우상단 FPS 카운터.
  • Layer borders: GPU 레이어 분리 시각화.

What — Renderer 측 최적화 (CSS·DOM)

가속을 켰을 때 더 잘 쓰려면 — 브라우저와 동일한 기법.

transform·opacity로 애니메이션

/* 나쁨: layout · paint 매 프레임 */
.box { left: var(--x); }
 
/* 좋음: compositor만 */
.box { transform: translateX(var(--x)); }

top/left/width/height 변경은 layout → paint → composite 모두 재실행. transform/opacitycomposite만. GPU 레이어로 분리되어 60fps 유지.

will-change로 레이어 promotion 힌트

.expensive-animation {
  will-change: transform, opacity;
}

브라우저에게 “이 요소는 곧 GPU 레이어가 될 거다” 미리 알려 promotion 비용을 분산. 과사용 금지 — 모든 요소에 will-change 붙이면 GPU 메모리 폭증.

③ Paint storm 잡기

// React에서 시간 표시를 매 ms 업데이트하면 →
//  매 ms마다 시간 텍스트 영역 repaint → CPU 100%
useEffect(() => {
  const t = setInterval(() => setNow(Date.now()), 1);  // 미친 짓
  return () => clearInterval(t);
}, []);

DevTools Performance 탭에서 long paint task를 잡아 — 영역을 transform only 애니메이션으로 격리.

④ 큰 이미지/canvas는 별도 레이어

canvas#stage {
  transform: translateZ(0); /* old-school promotion hack */
}

대형 canvas나 이미지가 DOM 위에 있을 때, GPU 레이어로 분리하면 주변 텍스트 repaint가 canvas에 영향 안 줌.


What-if — 잘못 결정한 결과

결정결과
모든 환경에서 disableHardwareAcceleration()일반 PC에서 60fps → 30fps, 비디오 재생 시 CPU 100%
모든 요소에 will-change: transformGPU 메모리 폭증 (~수백 MB), 오히려 OOM crash
top/left 애니메이션을 그대로 두기매 프레임 layout + paint, 큰 트리에서 jank
paint flashing 안 보고 추측으로 최적화엉뚱한 자리 깎기. 측정 우선
VDI 환경에서도 가속 켜기사용자가 5초 freeze. 회사 IT가 우리 앱 차단

흥미로운 이야기

Discord의 macOS 화면 캡처 버그는 GPU 가속이 만든 보안 흔적이다

2021년 macOS Big Sur에서 Discord 화면 공유검은 화면만 송출되는 버그가 있었다. 원인: Apple이 Metal renderer로 GPU 합성을 바꾸면서 외부 capture API합성된 프레임버퍼를 읽지 못하게 됨. 해결: Discord는 *해당 OS 버전에서만 disableHardwareAcceleration()*을 호출하도록 OS 감지 로직을 넣었다. 같은 시기 Slack은 같은 문제로 Linux에서 검은 화면을 겪었고, NVIDIA 독점 드라이버 + Wayland 조합에서만 GPU OFF를 강제하는 패치를 넣었다. 교훈: GPU 가속은 베스트 시나리오에서 빠르고, 수많은 변종 환경에서 흔들린다. 운영 중인 데스크톱 앱이 결국 OS·드라이버 매트릭스를 추적해야 한다는 게 잔혹한 진실 — Electron이 Chromium에 얹혀가는 건 90%이고, 나머지 10%는 우리가 책임진다.


Insight — 가속의 결정 매트릭스

가속 결정은 환경 분류 매트릭스. 우리 앱이 어떤 환경에서 실행되는지에 따라 런타임 결정을 해야 한다 — 빌드 타임이 아니라.


한 단락 요약

Chromium 렌더 파이프라인은 Layout → Paint → Composite → Display이고, “GPU 가속”은 Paint 일부 + Composite를 가속한다. 일반 PC에선 항상 ON이 빠르지만, VM·VDI·원격 데스크톱·일부 Linux에선 OFF가 빠르거나 깜빡임이 사라진다. chrome://gpu로 진단하고 app.disableHardwareAcceleration()런타임 환경 감지로 켠다. Renderer 쪽은 transform·opacity·will-changepaint storm을 피하면 가속의 효과가 극대화된다. 다음: 06-leaks-and-profiling — 메모리가 시간이 지나며 늘어나는 진짜 원인과 그 잡는 방법.