민프

[Flutter] Skia, Impeller 렌더링 엔진에 대해서 알아보자 본문

[Flutter]

[Flutter] Skia, Impeller 렌더링 엔진에 대해서 알아보자

민프야 2023. 8. 29. 17:08

Flutter의 핵심에는 대부분 C++로 작성되고, Flutter 애플리케이션을 지원하는데 필요한 Flutter 엔진이 있다.

그 Flutter 엔진에는 새 프레임을 칠해야 할 때마다 장면을 래스터화하는 역할을 하는데
렌더링을 담당하는 엔진은 Flutter 3.10에는 Impeller, 이전에는 Skia 렌더링 엔진이 있다.

 

이 두개의 렌더링 엔진에 대해서 알아보기 전에 렌더링이란 무엇인지부터 알아보자

렌더링이란?

렌더링이란UI 코드를 실제로 화면에 표시되는 픽셀로 변환하는데 도움이 되는 소프트웨어이다.

 

예를 들어서 위 와 같은 앱이 있다고 생각해보자

저 두번째 사진의 FlutterLogo가 첫번째 사진에서의 Flutter Framework가 되는 것 이다.

 

Flutter 프레임워크에서 위젯 트리는 세번째 사진에서와 같이 렌더링 객체트리로 뒷받침 되고,

렌더링 객체에는 실제로 위젯을 배치하고 페인트하는 방법, 스타일, 그래픽 효과 에 대한 지침이 포함되어있다. 

 

이러한 명령은 엔진에 제공되며 표시 목록(Display List)이라는 명령 목록에 저장된다.

 

Display List의 모든 항목은 사용 가능한 렌더러 중 하나인 Impeller 또는 Skia를 이용하여 GPU를 활용한 Render Pipeline 모음으로 설정을 합니다. 

 

그럼 GPU에서 어떻게 사물이 렌더링 되는지 알아보자

 

Render Pipeline  - 1. Tessellation

Render Pipeline을 사용하려면 Display List에서 그린 모든 경로를 가져와서 오른쪽 부분의 사진처럼 삼각형 세트로 테셀레이션을 해야합니다.

 

Render Pipeline  - 2. Vertex Shader

그런 다음 왼쪽 사진과 같이 삼각형의 각 정점이나 점은 정점 셰이더라는 것을 통과합니다.

Shader는 최종 사용자의 장치에서 사용 할 수 있는 GPU에서 컴파일하여 실행할 프로그램 입니다. 

정점셰이더 에서는 Flutter 로고를 구성하는 정점을 가져와 화면에서 실제로 그리려는 위치로 이동합니다.

 

삼각형을 확대한 아래 사진을 보면 

삼각형에 안에 있는 특정 픽셀을 파악하는데 이것을 Rasterzation(래스터화) 라고 합니다.  

 

Render Pipeline  - Stencil Test

래스터화가 끝난 후 각 삼각형에 대해서 색상을 계산해야하는지 결정하는 Stencil Test를 거치게 됩니다.

Render Pipeline  - Fragment Shader

이제 삼각형에 있는 모든 픽셀 프래그먼트 셰이더를 통해 전달이 됩니다.

프래그먼트 셰이더는 또 다른 코드 조각이지만

이번에는 정점 셰이더의 출력을 가져와 색상을 계산합니다. 

Render Pipeline  - Blending

마지막으로 Blending으로 색상만 교체하면 끝나게 된다. 

 

 

렌더링 엔진 - Skia 

Skia는 다양한 하드웨어 및 소프트웨어 플랫폼에서 작동하는 공통 API를 제공하는 오픈 소스 2D 그래픽 라이브러리입니다. Google Chrome과 Chrome OS, Android, Flutter 및 기타 많은 제품의 그래픽 엔진 역할을 합니다.

공식 홈페이지에 의하면 위 와 같이 설명하고 있는데 말 그대로 2D 그래픽 라이브러리 이다.

C++로 개발 되었고, OpenGL의 Canvas를 사용해서 렌더링을 한다.

즉, Flutter에서는 이 Skia를 통해 그려지는 것이고, Skia는 OpenGL를 통해 렌더링을 하게 되는 것이다. 

 

Skia엔진의 문제점은 결론적으로 Flutter용으로 설계되지 않았다는 것 이다.

그 말은 즉 Flutter에 최적화 되어있지 않다는 점 이다.


그럼 어떤 부분이 Skia의 문제점인지 파악해보자

Skia엔진의 문제점은?

위에서 언급한 Shader와 Render Pipeline들은 GPU가 실행할 수 있는 명령으로 컴파일되어야 하는데

이 과정에서 매우 많은 비용이 소모 됩니다.

 

Skia에서는 이 컴파일 프로세스가 프레임의 런타임에서 발생합니다. 

그래서 파이프라인은 실제로 무언가를 렌더링하는 데 사용되어야 하는데 Shader로 인해 일반적으로 프레임이 예산을 초과하여 눈에 띄는 끊김 현상이 발생하여 Shader 컴파일 Jank가 나오게 되는 문제가 발생되게 됩니다.

 

위 문제를 해결한게 Impeller 엔진입니다.

렌더링 엔진 - Impeller

Impeller 렌더링 엔진은 이번에 Google I/O 2023에서 새롭게 발표 된 렌더링 엔진입니다.

위에서 언급한 부분 처럼 Skia는 Flutter를 위해서 만들어진 엔진이 아니기에 위에서 언급한 대로 Flutter에 최적화 되어있지 않았는데요

 

Impeller엔진의 목표는

Flutter내에서 버벅거림이나 끊김 현상이 Skia엔진에서 문제가 발생하였는데 이것을 해결하는 것 입니다.

 

이러한 문제를 해결하기 위해서 Impeller는 Skia와 같은 방식으로 Shader를 생성하지 않습니다. 

Impeller는 Skia가 동적으로 생성하는 많은 특수 Shader에 비해 Flutter 엔진이 구동될 때 Impeller의 모든 Shader는 Impeller 씬 이라는 오프라인 Shader컴파일러를 통해 번들로 미리 컴파일이 됩니다.

 

근데 여기서 미리 컴파일된 여러 셰이더를 초기화하면 시작 시간이 느려지가나 플러터 앱 크기가 커질 수 있다는 단점이 있는데

위 문제를 방지하기 위해 Impeller는 Skia가 동적으로 생성하는 많은 특수 셰이더에 비해 훨씬 작고 단순한 셰이더 세트를 활용하는 대체 렌더링 기술을 사용합니다.

 

 아래 사진과 같이 실제로 Skia엔진과 Impeller의 성능을 비교해보면

오른쪽 그래프가 Impeller,

왼쪽 그래프는 Skia 입니다.

 

다음으로 Impeller 아키텍쳐에 대해서 알아보겠습니다. 

1 .Akis
Display List에서 -> Aiks  항목으로 전달됩니다.
Akis의 목표는 Display List에서 Draw Path, Draw Image와 같은 높은 수준의 명령을 가져와 Entity라고 하는 더 간단하고 독립적으로 그리기 작업으로 바꾸는 것  입니다. 

 

2. Entities Framework
Akis를 통해 Display List에서는 고유한 Entity를 가지게 되는데요 
각 Entity에서는 위치, 회전 및 배율을 인코딩하는 변환 행렬과 같이 모든 단일 그리기 작업에 필요한 여러 속성이 포함되어 있고, Entity를 그리는데 필요한 실제 GPU명령이 포함된 콘텐츠 개체도 할당 됩니다. 
해당 단계를 지나면 아래 사진과 Flutter 로고의 쿼드 4개는 모두 단색으로 SolidColorContents가 할당 됩니다.

3. Hard Abstraction Layer(하드웨어 추상화 계층)

Flutter 앱은 다양한 플랫폼에서 실행될 수 있기 때문에 Impeller는 GPU와 통신하기 위해 일종의 변환 레이어가 필요합니다.

이것을 Hard Abstraction Layer(하드웨어 추상화 계층)계층이라고 한다.

IOS의 Metal 및 Android의 Vulkan과 같은 다양한 표준 그래픽 API를 통해 그래픽 드라이버와 통신하는 얇은 추상화 입니다. 

 

위에서 언급한 Render Pipeline에서 이 HAL을 사용하여서 아래 사진에서와 같이 실제로 사용하려는 Shader가 포함된

렌더 파이프라인을 실행하도록 GPU에 지시함으로써 자체적으로 그려지게 되는 것 입니다.


참고링크

https://docs.flutter.dev/perf/impeller

 

Impeller rendering engine

What is Impeller and how to enable it?

docs.flutter.dev

 

Comments