UI 최적화에 관한 이 일련의 주제에서는 Android 렌더링과 관련된 지식에 대해 이야기하겠습니다. 이는 주로 UI 렌더링 배경 지식과 UI 렌더링 최적화 방법의 두 부분으로 구성됩니다.
"View 그리기 프로세스에서 setContentView()는 정확히 무엇을 합니까? 》
"보기 그리기 과정: 창에 DecorView를 추가하는 과정"
"심층 활동 3부작 (3) 보기 그리기 과정"
" Android LayoutInflater 종합 분석》
《렌더링에 대해 알아야 할 사항은 무엇인가요? 》
《Android Choreographer의 상세 분석》
《Android에서 UI 렌더링을 최적화하는 방법(1부)》
《Android에서 UI 렌더링을 최적화하는 방법 (2부) 》
Google은 2012년 I/O 컨퍼런스에서 Project Butter를 발표하고 Android 4.1에서 이 메커니즘을 공식 출시했습니다.
Project Butter는 크게 두 가지 구성 요소로 구성됩니다. 하나는 VSYNC이고 다른 하나는 Triple Buffering입니다.
안드로이드의 평판에 심각한 영향을 끼쳤던 UI 플루언시 문제가 효과적으로 해결된 것도 이때부터였다. 오늘 우리는 이 두 구성요소의 작동 원리에 대해 이야기할 것이지만, 이를 이해하기 전에 관련된 다른 두 가지 개념을 살펴봐야 합니다.
화면이 1초 내에 화면을 새로 고침함을 나타냅니다. 이때 새로 고침 빈도는 하드웨어의 고정 매개변수에 따라 달라지며 단위는 HZ(Hz)입니다. 예를 들어, 초당 60회 새로 고쳐지는 일반적인 60Hz입니다.
프로그레시브 스캐닝
모니터는 화면에 사진을 한 번에 표시하는 것이 아니라 왼쪽에서 오른쪽, 위에서 아래로 점진적으로 스캔하여 표시하는데 이 과정이 빠릅니다. 60Hz 새로 고침 빈도, 즉 1000/60 ≒ 16ms의 화면을 예로 들면 변화는 눈에 띄지 않습니다.
GPU가 1초에 그리는 프레임 수를 나타냅니다. 예를 들어 영화는 24fps를 사용하고 Android 시스템은 60fps를 사용합니다. 이는 1초에 30/60 프레임이 그려지는 것을 의미합니다. 자세한 내용은 "왜 60fps인지"를 참조하세요.
이제 그래픽 콘텐츠가 화면에 나타나도록 하려면 새로 고침 빈도와 프레임 속도가 함께 작동해야 합니다. GPU는 그리기 위한 그래픽 데이터를 얻은 다음 하드웨어가 이미지 콘텐츠를 표시하는 역할을 합니다. 이 프로세스는 애플리케이션의 수명 주기 동안 계속해서 발생합니다.
안타깝게도 새로 고침 빈도와 프레임 속도가 항상 상대적으로 동기화되는 것은 아닙니다. 예를 들어 프레임 속도가 실제로 새로 고침 빈도보다 빠른 경우 프레임 속도는 120fps이고 모니터의 새로 고침 빈도는 60입니다. . 이 시점에서 몇 가지 시각적 문제가 발생합니다.
모니터는 한 줄씩 스캔하여 왼쪽에서 오른쪽, 위에서 아래로 이미지를 추출하므로 이 프로세스에는 GPU가 메모리 영역을 사용하여 프레임 데이터를 쓸 때 16ms(1000/60)가 소요됩니다. 새 프레임은 위에서부터 시작하여 이전 프레임을 덮어쓰고 즉시 한 줄의 내용을 출력합니다. 화면이 새로 고쳐지면 이미지 버퍼의 상태를 알 수 없으므로 GPU에서 가져오는 프레임은 완전한 데이터가 아닙니다. 즉, 이전 프레임의 절반과 현재 프레임의 절반이 있는 상황을 화면 찢어짐이라고 합니다.
이 문제에 대한 해결책은 GPU와 모니터 모두 자체 작업 버퍼를 갖는 이중 버퍼링입니다.
GPU는 항상 드로잉 데이터의 완성된 프레임을 백 버퍼에 쓰는 반면, 모니터는 프레임 버퍼를 사용합니다. 화면이 새로 고쳐질 때 프레임 버퍼는 변경되지 않습니다. Back Buffer는 VSYNC가 들어오는 화면 새로 고침에 따라 데이터를 Frame Buffer로 복사합니다.
Android 4.1 이전에는 Android에서 이중 버퍼링 메커니즘을 사용했습니다. 그것을 이해하는 방법? 일반적으로 동일한 뷰 계층 구조의 뷰는 하나의 창, 즉 하나의 표면을 사용합니다.
각 Surface에는 BufferQueue 캐시 대기열이 있지만 이 대기열은 SurfaceFlinger에 의해 관리되며 익명 공유 메모리를 통해 앱 애플리케이션 계층과 상호 작용합니다.
전체 프로세스는 다음과 같습니다.
Android는 화면 잘림을 방지하기 위해 항상 VSYNC를 사용했습니다. Android 4.0의 경우 CPU가 UI 그리기를 처리하는 데 시간이 부족할 수 있습니다. 다른 것들. 따라서 4.1 VSYNC부터 한 단계 더 발전하여 이제 VSYNC 펄스를 사용하여 다음 프레임의 모든 처리를 시작합니다.
VSYNC는 VSYNC 인터럽트가 수신될 때마다 CPU가 즉시 버퍼 데이터를 준비하는 것과 유사합니다. 대부분의 디스플레이 장치의 새로 고침 빈도는 60Hz(초당 60회 새로 고침)입니다. 즉, 데이터의 한 프레임입니다. 준비 작업은 16ms(1000/60≒16) 이내에 완료되어야 합니다.
이런 방식으로 애플리케이션은 항상 VSYNC 경계에서 그리기 시작하고 SurfaceFlinger는 항상 VSYNC 경계에서 구성합니다. 이를 통해 끊김 현상이 제거되고 그래픽의 시각적 표현이 향상됩니다.
이중 버퍼링 메커니즘의 원리를 이해하면 삼중 버퍼가 무엇인지 이해하는 것은 매우 쉽습니다. 그래픽 버퍼 버퍼 A와 B가 두 개만 있는 경우 CPU/GPU 그리기 프로세스가 길고 하나의 VSYNC 신호 기간을 초과하는 경우 버퍼 B의 데이터가 아직 준비되지 않았기 때문에 버퍼 A의 내용은 계속해서만 유지될 수 있습니다. 따라서 버퍼 A와 B는 각각 디스플레이 장치와 GPU에 의해 점유되고 CPU는 다음 프레임을 위한 데이터를 준비할 수 없습니다.
다른 버퍼가 제공되면 CPU, GPU 및 디스플레이 장치는 모두 자체 버퍼를 사용하여 서로 영향을 주지 않고 작동할 수 있습니다. 간단히 말하면, 트리플 버퍼 메커니즘은 더블 버퍼 메커니즘에 그래픽 버퍼 버퍼를 추가하여 유휴 시간의 활용을 극대화할 수 있는 방식입니다. 단점은 그래픽 버퍼가 하나 더 차지하는 메모리를 사용한다는 것입니다.
그림에서 볼 수 있듯이 버퍼 B는 너무 오래 걸리고 A를 사용하여 현재 프레임을 표시하고 있습니다. 그러나 이번에는 중복 버퍼에 시간을 낭비하는 대신 시스템이 C 버퍼를 생성하고 다음 프레임 처리를 시작합니다. 삼중 버퍼링은 버벅거림의 추가 악화를 줄여줍니다.
트리플 버퍼링이 항상 존재하는 것은 아닙니다. 일반적으로 더블 버퍼만 실행되지만 지연 및 기타 상황이 발생하면 지연 시간 증가를 줄이기 위해 세 번째 버퍼가 나타납니다.
VSYNC 신호 및 삼중 버퍼링에 대한 자세한 소개는 "프로젝트 버터 - 작동 방식 및 추가된 내용은 무엇입니까?"를 참조하세요. 》.
Android 렌더링 프레임워크는 매우 규모가 크며 매우 빠르게 발전하고 있습니다. 관심 있는 친구들은 아래 참고 자료를 더 자세히 읽어볼 수 있습니다.