공부/flutter

[Flutter] 렌더링 엔진

iris3455 2025. 10. 17. 19:34

렌더링

렌더링은 컴퓨터 프로그램을 활용하여 2D 또는 3D 모델에서 최종 이미지를 생성하는 프로세스이다. 이 과정에서 최종 이미지를 얻을 때까지 텍스처, 조명 및 카메라 각도를 포함한 모든 작은 세부 정보가 원시 모델에 제공된다.

 

 

CPU렌더링

장점

  1. 호환성: 거의 모든 시스템에서 사용할 수 있으며, 다양한 렌더러와 호환된다.
  2. 메모리 용량: 일반적으로 GPU보다 더 많은 RAM을 사용할 수 있어, 매우 복잡한 장면을 렌더링할 수 있다.
  3. 정밀도: CPU 렌더링은 높은 정밀도와 복잡한 계산을 처리하는 데 강력하다.

단점

  1. 속도: 일반적으로 GPU 렌더링보다 느리다.
  2. 확장성: 속도를 높이기 위해 추가 CPU를 설치하는 것은 제한적이다.

 

 

GPU렌더링

장점

  1. 속도: 병렬 처리가 뛰어나므로, 일반적으로 CPU 렌더링보다 훨씬 빠르다.
  2. 실시간 피드백: 빠른 렌더링 속도로 인해 실시간 프리뷰 및 피드백이 가능하다.
  3. 효율성: 복잡한 씬을 빠르게 처리할 수 있어, 반복 작업에 유리하다.

단점

  1. 메모리 제한: GPU의 VRAM 용량이 제한적이므로, 매우 복잡한 장면에서는 메모리 부족 문제가 발생할 수 있다.
  2. 호환성: 모든 렌더러가 GPU를 지원하는 것은 아니며, 특정 GPU 렌더러와의 호환성 문제도 있을 수 있다.
  3. 비용: 고성능 GPU는 비용이 높을 수 있다.
  4. 정밀도: CPU 렌더링에 비해 낮은 정밀도를 보인다.

 

 

Flutter 렌더링 엔진

Flutter는 강력한 UI 프레임워크로서 빠른 렌더링을 제공하기 위해 모든 화면을 GPU(OpenGL, Vulkan, Metal 등) 위에서 직접 그린다. 즉 “플랫폼의 기본 UI(View, UIKit)”를 쓰는 게 아니라 구글에서 만든 자체 엔진을 사용하는데 기존에는 Skia 엔진을 사용하여 다양한 플랫폼에서 일관된 그래픽 성능을 보장했다. 하지만 성능 향상과 최적화를 위해 Flutter 팀은 새로운 렌더링 엔진인 Impeller를 도입했다.

 

Skia

Flutter는 기본적으로 Skia라는 2D 그래픽 엔진을 사용하여 UI를 렌더링한다. Skia는 Chrome, Android 등에서도 사용되는 강력한 오픈소스 그래픽 라이브러리로, 벡터 그래픽, 글꼴 렌더링, 비트맵 이미지 등을 처리하는 기능을 제공한다. 하지만 Skia를 활용한 Flutter의 렌더링 방식에는 몇 가지 한계가 있다.

  • 실시간 셰이더 컴파일 문제
    • Flutter의 애니메이션 및 UI 변화를 처리할 때, 셰이더(Shader)를 즉석에서 컴파일하는 과정에서 지연(Jank)이 발생하는 경우가 많음
  • Metal 및 Vulkan 최적화 부족
    • iOS에서는 Metal API를, Android에서는 Vulkan API를 활용해야 고성능 그래픽 처리가 가능하지만, Skia는 이를 완벽하게 활용하지 못함

 

Impeller

이러한 문제를 해결하기 위해 Flutter 3.10부터 iOS에서 기본 렌더링 엔진이 Skia에서 Impeller로 변경되었다. Impeller는 GPU 최적화에 초점을 맞춘 새로운 렌더링 엔진으로, Skia보다 더 나은 성능과 안정성을 제공한다.

  • 셰이더 사전 컴파일(Precompiled Shader)
    • 기존 Skia에서는 실시간으로 셰이더를 컴파일하면서 지연이 발생했지만, Impeller는 앱 실행 전에 셰이더를 미리 컴파일하여 성능 문제를 해결함
  • Metal 및 Vulkan 완전 지원
    • Impeller는 iOS에서는 Metal, Android에서는 Vulkan을 적극적으로 활용하여 최적화된 성능을 제공
  • 더 빠르고 부드러운 애니메이션
    • Skia 기반의 Flutter 앱에서는 화면 전환이나 애니메이션에서 간헐적으로 끊김이 발생할 수 있었지만, Impeller는 이를 개선하여 부드러운 애니메이션을 제공함

 

 

Flutter GPU 렌더링 과정

Flutter는 기본적으로 CPU를 통해 렌더링 실행, GPU를 활용하여 UI를 렌더링하며, 렌더링 과정은 다음과 같다.

 

 

1. 위젯 트리 (Widget Tree) 구성 — CPU

  • 사용자가 작성한 Flutter 코드가 실행
build(BuildContext context) => Container(color: Colors.red);
  • Flutter는 이를 기반으로 Widget Tree를 생성
    • 이는 선언형 구조로, 화면에 표시할 UI의 “청사진”. 이 단계에서는 “무엇을 보여줄지”만 정의될 뿐, 실제 렌더링은 아직 이루어지지 않음

 

2. 엘리먼트 트리 (Element Tree) 생성 — CPU

  • Widget은 불변(immutable)이기 때문에, 실제 상태를 담기 위해 Element Tree가 만들어진다.
  • Element는 Widget의 인스턴스이며, BuildContext를 통해 서로 연결된다.
  • 위젯의 생명주기(initState → build → dispose)가 관리된다.
    • 즉, Widget은 설계도, Element는 실제 인스턴스(상태).

 

 

3. 렌더 오브젝트 트리 (RenderObject Tree) 생성 — CPU

  • UI를 실제로 그릴 수 있는 구조(Render Tree)로 변환
  • 각 RenderObject는 자신의 크기, 위치, 자식 관계를 알고 있다.

 

4. Layout 단계 — CPU

  • 부모 → 자식 순서로 위젯 크기와 위치를 계산한다.
  • Flutter의 레이아웃 시스템은 다음 두 단계를 거친다.
    1. Constraints 전달: 부모가 자식에게 가능한 크기 제시
    2. Size 결정: 자식이 그 제약 안에서 자신의 크기를 결정

이 결과, 모든 RenderObject의 위치·크기가 확정된다.

 

 

5. Paint 단계 — CPU

  • 이제 각 RenderObject가 “어떻게 그릴지”를 명령으로 기록합니다.
  • Flutter는 이 명령을 DisplayList(Skia의 추상 그래픽 명령 리스트)에 저장한다.
    • 예: “이 좌표에 사각형을 그려라”, “이 색상으로 채워라” 등
  • 이 Paint 명령들은 아직 화면에 표시되지 않는다.
    • CPU가 GPU에게 전달할 렌더링 지시서를 만드는 단계이다.

 

6. Layer Tree 구성 — CPU

  • 여러 위젯들이 모여 화면 전체를 구성하므로, Flutter는 이를 Layer Tree로 관리한다.
    • Layer Tree는 “화면의 최종 합성 순서”를 GPU에 알려주는 구조이다.

 

RepaintBoundary는 여기서 중요한 역할을 한다.
이 위젯을 경계로 Layer가 분리되어 GPU 리렌더링 범위를 줄일 수 있다.

 

 

 

7. GPU로 전달 (Raster Thread 진입)

  • Flutter는 렌더링을 두 개의 스레드로 나눠 병렬 처리한디.
    • UI Thread (Dart) → 위 단계까지 수행 (위젯 빌드, 레이아웃, 페인트)
    • Raster Thread (C++) → 실제 GPU 렌더링 수행

 

 

 

8. Rasterizer가 Skia 엔진을 통해 GPU 명령 생성 — GPU

  • Rasterizer가 Layer Tree를 받아 Skia 엔진에 전달한다.
  • Skia는 이를 OpenGL / Vulkan / Metal API 명령으로 변환한다.
    • 예: “drawRect”, “drawPath”, “drawImage” 등의 GPU 명령 호출
  • 이 시점부터 모든 연산은 GPU에서 수행된다.

 

9. GPU가 실제 픽셀 렌더링 — GPU

  • GPU는 받은 명령을 처리하여 실제 픽셀 단위로 화면을 그린다.
    1. Vertex Shader — 각 도형의 꼭짓점 계산
    2. Fragment Shader — 각 픽셀의 색상 계산
    3. Frame Buffer에 렌더링 결과 저장
  • 이 과정을 1초에 60~120번 반복하며(프레임 레이트), Flutter는 16.6ms 이내에 한 프레임을 완성하도록 목표한다.

 

10. 합성(Compositing) 후 화면 출력 — GPU

  • GPU는 모든 Layer를 합성(Compositing)하여 실제 화면 버퍼(Surface)에 최종 이미지를 출력한다.
  • 이 결과물이 사용자가 보는 한 프레임(Frame)이다.