탐색으로 돌아가기
Browser16 / 24 단계

Composite

레이어 합성

페인트된 레이어들을 올바른 순서로 겹쳐(합성) 하나의 화면으로 완성한다. GPU가 담당한다.

컴포지트(Composite)는 페인트로 래스터화된 여러 레이어를 최종 화면 이미지로 합성하는 마지막 단계로, 이 작업은 메인 스레드가 아닌 별도의 컴포지터 스레드(compositor thread)에서 수행되어 메인 스레드가 바쁜(JS 실행 등) 동안에도 스크롤과 애니메이션이 부드럽게 유지된다. 브라우저는 페인트 결과인 디스플레이 리스트를 레이어 트리(layer tree)로 나누고(layerize), 각 레이어를 타일(tile) 단위로 GPU에서 래스터화한 뒤, 위치·클립·시각효과를 담은 프로퍼티 트리(transform, clip, effect, scroll)를 적용해 GPU가 텍스처들을 겹쳐 그린다. transform과 opacity는 레이아웃·페인트를 건드리지 않고 이 컴포지터 단계에서만 처리되기 때문에 애니메이션을 메인 스레드에서 완전히 오프로드해 60fps(프레임당 약 16.6ms)를 안정적으로 달성할 수 있다. 개발자는 will-change: transform 등으로 요소를 미리 레이어로 승격(layer promotion)해 힌트를 줄 수 있으나, 레이어마다 GPU 메모리가 들기 때문에 과도한 승격은 오히려 성능을 해친다.

내부 구성

컴포지터 스레드 (Compositor Thread)
메인 스레드와 분리되어 스크롤·합성·애니메이션을 처리. 메인이 블록돼도 화면을 부드럽게 유지
레이어라이즈 (Layerize)
디스플레이 리스트를 독립적으로 래스터화 가능한 합성 레이어 목록으로 분할하는 단계
레이어 트리 (Layer Tree)
합성 대상 레이어들의 계층 구조. 각 레이어는 개별 텍스처로 GPU에 올라감
타일 (Tiles)
레이어를 잘게 나눈 래스터 단위. 뷰포트 근접도로 우선순위를 매겨 GPU 메모리를 배분
GPU / Viz 프로세스
타일 텍스처를 실제로 래스터화하고 합성 프레임을 화면에 그리는 하드웨어 실행 주체
Transform 프로퍼티 트리
이동·회전·스케일 등 좌표 변환을 인코딩. 레이아웃 없이 레이어 위치를 바꿈
Clip 프로퍼티 트리
각 레이어에 적용되는 잘라내기(clip) 영역을 표현
Effect 프로퍼티 트리
opacity, filter, mask, blend mode 등 모든 시각 효과를 인코딩
Scroll 프로퍼티 트리
스크롤 오프셋을 표현. 컴포지터가 메인 스레드 없이 스크롤을 처리하게 함
레이어 승격 (Layer Promotion)
요소를 별도 합성 레이어로 올려 리페인트를 격리하고 컴포지터에서만 애니메이션되게 함
will-change
곧 변할 속성을 브라우저에 미리 알려 레이어를 선제적으로 준비시키는 힌트 속성
커밋 (Commit)
메인 스레드의 프로퍼티 트리·디스플레이 리스트를 컴포지터 스레드로 복사해 동기화하는 단계

핵심 포인트

  • 컴포지트는 여러 레이어를 GPU에서 겹쳐 최종 화면을 만드는 마지막 단계
  • 컴포지터 스레드는 메인 스레드와 분리 → 메인이 바빠도 스크롤·애니메이션 유지
  • 레이어 트리로 분할(layerize) 후 각 레이어를 타일 단위로 GPU 래스터화
  • 프로퍼티 트리 4종: transform, clip, effect(opacity/filter/mask), scroll
  • transform·opacity는 layout·paint를 건너뛰고 컴포지트만 → 가장 저렴, 60fps 달성
  • will-change / 레이어 승격(promotion)으로 미리 레이어화 힌트 제공
  • 레이어 남용은 GPU 메모리 폭증(layer explosion)으로 역효과 → 필요한 곳에만

심화

가장 중요한 실무 교훈은 '합성만 하는(compositor-only) 속성'인 transform과 opacity로 애니메이션을 만들라는 것이다. 이 두 속성은 프로퍼티 트리(transform tree, effect tree)만 갱신하면 되므로 레이아웃·페인트·심지어 커밋 이후의 메인 스레드 개입 없이 컴포지터 스레드에서 완전히 처리된다. 그래서 메인 스레드가 무거운 JS로 막혀 있어도 60fps 애니메이션이 유지된다. 반대로 left/top이나 width/height로 움직이면 매 프레임 리플로우+리페인트가 나서 프레임을 놓친다. RenderingNG 파이프라인에서 '애니메이션·스크롤·시각효과는 layout·pre-paint·paint를 건너뛸 수 있다'고 명시하는 이유가 이것이다. will-change의 양날성도 면접 단골이다. will-change: transform은 레이어를 미리 만들어 애니메이션 시작 시 페인트 지연(레이어 생성 비용)을 없애주지만, 상시 걸어두면 그만큼 GPU 메모리를 계속 점유하고 레이어 폭발(layer explosion)을 일으켜 오히려 합성 비용과 메모리를 늘린다. 원칙은 '애니메이션 직전에 켜고 끝나면 끄기', 그리고 남용 금지다. 컴포지터 아키텍처의 핵심 통찰은 '메인 스레드 절반(layer tree)과 impl 스레드 절반(pending/active tree)의 분리'로, impl 트리는 메인이 블록된 순간에도 이미 래스터된 타일로 다음 프레임을 그릴 수 있어 스크롤 지터를 막는다는 점이다. Chrome DevTools의 Layers 패널과 Rendering 탭의 'Layer borders'/'FPS meter'로 실제 레이어 수와 합성 성능을 검증하는 습관이 실무의 마무리다.

쉽게 말하면 투명 필름(레이어) 여러 장을 순서대로 겹쳐 하나의 완성된 그림으로 만드는 것.

면접 예상 질문

#Composite#GPU#레이어#transform#will-change