Impeller engine

강정우·2024년 6월 20일
2

Flutter&Dart

목록 보기
80/87
post-thumbnail

플러터는 사실 굉장히 복잡한 옵션질을 할 수 있다.
알면 알 수록 굉장히 옵션질 할 수 있는게 늘어나서 아는게 많으면 무조껀 이득이다.

Impeller engine

임펠러 엔진이 뭔가?
원래 플러터는 skia engine 을 사용했다. 하지만 이 스키아 엔진은 플러터에 최적화 되어있지 않고 다양한 하드웨어 및 소프트웨어 플랫폼에서 공통 API를 제공하는 오픈 소스 2D 그래픽 라이브러리이다.

구글 크롬, Chrome OS, Android, Flutter, Firefox, Firefox OS 등 많은 다른 제품들의 그래픽 엔진 역할을 한다.

그럼 어떻게 스키아가 플러터 엔진으로 채택 될 수 있었을까? 바로 OpenGL 을 사용하기 때문이다.
Skia는 C++로 개발된 오픈 소스 2D 그래픽 라이브러리로 OpenGL의 Canvas를 사용해 렌더링을 하기 때문에 플러터 엔진으로 사용할 수 있었던 것이다.

그걸 이제 임펠러 엔진이 해준다.

그럼 위 사진에서 렌더러가 뭐냐 => 내 UI 코드를 pixel 로 바꿔주는 역할을 한다.

플러터 동작 과정을 보면 내가 작성한 widget 코드는 렌더 오브젝트(어떻게 위젯을 그리라고 설명을 포함하고 있음.)가 있고 이걸 엔진(렌더러(스키아, 임펠러))한테 주는데 이걸
정렬된 list 로 저장한다. 그리고 이걸 display list 라고 부른다.


그리고 이 렌더러가 이 display list 를 surface texture 에 그려낸다.
display list의 모든 항목을 GPU를 활용하여 Render Pipeline 모음으로 설정한다.


그런데 render pipeline을 사용하려면 먼저 display list가 그린 모든 경로를 가져와 삼각형 세트로 테슬레이션 해야한다.
이 테슬레이트 된 삼각형들이 쉐이더를 지나 레스터리제이션(rasterization: 선 모양이 구체적으로 어느 픽셀에 위치할 것인지 정하는 것)을 지나 fragement shader 를 지나 아래 사진 처럼 최종적으로 렌더링 되는 것이다.

그럼 이 렌더 파이프 라인이 어떻게 구체적으로 임펠러 엔진에서 구현되었는지 확인해보자

Impeller Architecture

먼저, 모든 display list 작업은 Aiks라는 것으로 보내진다.

Aiks는 임펠러의 최상위 층이다. (Skia 의 역순인건 안 비밀)
그리고 주로 캔버스 드로잉 API로 구성되어 있다.

Aiks의 작업은 드로 패스 및 드로잉 이미지와 같은 높은 수준의 명령어를 display list 에서 가져와서 entity라고 하는 단순하고 독립적인 드로잉 작업으로 변환하는 것이다.

각각의 엔티티는 매우 많은 속성값을 지닐 수 있다. like 모든 각각의 drawing 을 operation 할 때 반드시 필요한.
그리고 각각의 엔티티는 Contents 라고 하는 것들을 할당받는데 이 Contents 가 뭐냐면 entity 를 그릴 때 필요한 GPU instruction 이다.
뭐, 예를 들어 색깔, 텍스쳐, 그라데이션, 텍스트, 클립 등

근데 Aiks 가 미친게 "상황에 따라" 렌더링 할 때 가장 최적화된 알고리즘을 "선택" 하여 그린다.

이제 Entities Framework 가 끝나면 여기서는 이제 GPU 가 인식할 수 있는 언어로 변환해줘한다.
그리고 바로 Harware Abstaraction Layer 에서 Metal(iOS 용), Vulkan(Andoird 용), OpenGl(Web) 등으로 변환해준다.
그럼 이제 GPU 가 지가 뭘 할지 알아먹었을 것이다.
그럼 이제 아래 사진이 동작하는 것이다.

그런데 여기서 개반전이 있다. shader 와 render pipeline 도 GPU가 실행할 수 있는 명령어로 컴파일해야 한다.
문제는 Skia에서는 이 컴파일 과정을 프레임의 런타임에서 발생한다.
파이프라인은 실제로 무언가를 렌더링하는 데 사용되어야 하는데 이 작업이 생각보다 비싼 작업이기에 눈에 띄게 버벅인다.
그리고 이것을 우리는 종종 이 문제를 "쉐이더 컴파일 쟁크"라고 부른다.

하지만 Impler는 이 컴파일에서 가장 비용이 많이 드는 부분을 미리 수행함으로써 이 문제를 크게 개선했다고 한다.

바로 여기서! flutter engine 이 build 가 되면 모든 임펠러 쉐이더들이 Impeller scene 이라 불리는 컴파일을 사용하여 번들로 컴파일 된다.

무튼 바로 이렇게 GPU 와 직접적으로 통신하기 때문에 졸라 부드럽고 빠른, 그리고 별다른 의존성 없이 개발이 가능한 부분이라고 말할 수 있다.

key architecture decisions

앞서 우리는 이 임펠러 엔진이 jank 를 없애고 skia 처럼 쉐이더를 generate 하지 않는다고 하였다.

이로인해 임펠러는 미리 컴파일된 여러 세이터를 초기화하면 시간 시간이 느려지거나 플러터의 앱 크기가 커질 수 있다고 생각할 수 있다.
하지만 이를 막기위해 Skia가 동적으로 생성하는 많은 특수 셰이더에 비해 훨씬 작고 단순한 셰이더 세트를 활용하는 대체 렌더링 기술을 사용한다.

예를들어 Anti-Aliasing 이다. MSAA 칩이 매우 가볍지만 최상의 결과를 도출해준다.
또 다른 기술은 Clipping 이다. 플러터는 휴대폰의 하드웨어를 사용하여 clip masks 를 사용하여 모양을 잡아주기 때문에 매우 빠르며 아주 중요한 작업이다.

Impeller는 Flutter용으로 맞춤 제작되었으며 Flutter 엔진의 핵심 부분을 크게 재작성 하여 이전 Skia 코드를 iOS의 Metal 및 Vulkan과 같은 최신 하드웨어 가속 그래픽 API를 최대한 활용하는 맞춤 런타임으로 대체한다.

profile
智(지)! 德(덕)! 體(체)!

0개의 댓글