브라우저가 그리는 법

adultlee·2023년 10월 23일
95
post-thumbnail

이런 분들께 이 글을 추천합니다.

  1. 브라우저의 렌더링 동작에 대해 "기초적인" 지식이 있으신 분
  2. 브라우저 렌더링 과정 중 Rendering에 집중 해보고 싶은 분
  3. 이 글의 전 단계인 브라우저가 읽는 법 을 읽고 오신분

이 글의 순서는 다음과 같습니다.

  1. 서문
  2. 렌더링 과정의 훌륭한 일꾼들
  3. 렌더 트리는 어떻게 만들어지는 걸까? (Render Tree)
  4. 어떻게 배치되는거지 (Layout)
  5. 그려질 순서를 정해보자 (Layer)
  6. 어떻게 그릴 수 있을까 (Paint)
  7. 어떻게 나눠서 그릴 수 있을까? (Tilling)
  8. 픽셀로 변환해보자 (raster)
  9. 모든걸 더해서 만들어보자 (Compositing)
  10. 파이프라인

0. 서문

면접관 : 주소창에 www.google.com을 입력했을때 일어나는 과정에 대해서 설명해보세요.

다음과 같은 질문을 얼마나 많이 들어보셨나요?
정말 많은 글에서도 강조되고 언급되는 만큼 웹개발자에게 중요한 질문으로 자리잡고 있습니다.

Rendering Engine이 동작하여 화면에 google을 그리는 과정을 표시한 도식도 입니다.

저도 마찬가지로 웹 개발자로서 정말 여러번 마주하는 개념이었는데요.
한번 공부하는김에 제대로 공부를 진행해보고 싶어. 이번 기회에 오로지 Rendering만 담아서 학습을 진행해보려 합니다.

1. 렌더링 과정의 훌륭한 일꾼들

브라우저의 렌더링 과정에는 아주 훌륭한 일꾼들이 여럿있습니다.
브라우저 렌더링 과정에 대해서 설명하기 위해선 이 일꾼들에 대한 설명이 필수적인데요! 차근차근 하나씩 설명을 진행해 보겠습니다!

메인 스레드(Main Thread)란?

가장 중요한 스레드! 하지만 몸이 하나야...

메인 스레드는 웹 브라우저에서 웹 페이지의 주요 처리를 담당하는 중추적인 스레드입니다. 웹 브라우저의 렌더링 및 동작 과정에서 다양한 역할을 수행하며, 그 특징과 역할에 대해서 학습해 보겠습니다.

메인스레드의 4가지 특징

  1. 웹 서버로부터 받아온 HTML 문서를 파싱하여 DOM (Document Object Model) 트리를 생성합니다. 외부 리소스(예: 이미지, 스크립트, 스타일시트)를 만나면 해당 리소스를 다운로드합니다.

  2. 메인 스레드는 JavaScript 코드를 실행합니다. DOM API를 통해 웹 페이지의 구조나 스타일을 동적으로 변경할 수 있습니다. JavaScript의 실행은 메인 스레드에서 동기적으로 처리됩니다.

  3. 사용자의 마우스 클릭, 키보드 입력, 터치 이벤트 등을 처리합니다.

  4. 렌더링과정 전체에 관여하며 통제(다른 스레드에 일을 나눠줍니다!)

  • 웹 서버로부터 받은 HTMLCSS를 파싱하여 DOM 트리CSSOM 트리를 생성합니다.
  • JavaScript메인 스레드에서 실행됩니다. 이를 통해 DOM이나 CSSOM을 조작하거나 이벤트 핸들러를 처리할 수 있습니다.
  • DOM 트리CSSOM 트리를 합쳐서 렌더 트리를 생성합니다. 렌더 트리는 화면에 실제로 그려질 요소와 그 요소의 스타일 정보를 포함합니다.
  • 렌더 트리를 기반으로 각 요소의 정확한 위치와 크기를 계산합니다.

하지만...

메인 스레드는 단일 스레드로 동작하기 때문에 한 번에 하나의 작업만 처리할 수 있습니다.
따라서, 오래 걸리는 작업이 실행되면 다른 작업들이 대기 상태(Blocking)에 놓이게 되어 웹 페이지의 반응성이 떨어질 수 있습니다.
이러한 문제를 해결하기 위해 웹 워커나 비동기 처리 방식을 사용하여 메인 스레드의 부하를 줄일 수 있습니다.
또한 4번의 렌더링 과정에 메인스레드가 실질적으로 처리하는 비중이 적다고 생각하실 수도 있는데요!
그 이유는 메인스레드가 단일 스레드이며, 블라킹 되는 과정을 최소화 하기 위해 다른 스레드에 일을 위임하기 때문입니다!

컴포지터 스레드(Compositor Thread)란?

합성과정을 담당하는 친구!

컴포지터 스레드는 브라우제 렌더링 과정중 합성 단계에서 매우 중요한 역할을 수행합니다. 합성 단계는 웹 페이지의 다양한 레이어(layer)나 요소들을 올바른 순서로 합치는 과정인데, 이 작업이 효율적으로 이루어져야 웹 페이지의 성능이나 사용자 경험이 좋아집니다. 컴포지터 스레드의 주요 역할과 중요성을 다음과 같이 요약할 수 있습니다:

  1. 부드러운 애니메이션 및 스크롤: 웹 페이지에서 발생하는 애니메이션, 스크롤, 트랜지션 등의 변화를 감지하고 해당 부분만을 업데이트하여 화면에 표시하도록 합니다. 이를 통해 사용자에게 부드러운 웹 경험을 제공합니다.

  2. GPU 최적화: 컴포지터 스레드는 GPU(Graphics Processing Unit)를 활용하여 합성 작업을 빠르게 처리합니다. 이를 통해 CPU의 부하를 줄이고 더 빠른 렌더링 성능을 얻을 수 있습니다.

  3. 레이어 관리: 웹 페이지의 각 요소는 다양한 레이어에 위치할 수 있습니다. 컴포지터 스레드는 이러한 레이어들을 효율적으로 관리하고, 필요한 레이어만을 업데이트하여 성능을 최적화합니다.

  4. 효율적인 리소스 관리: 컴포지터 스레드는 필요한 리소스만을 사용하여 합성 작업을 수행합니다. 예를 들어, 화면에서 보이지 않는 영역의 요소는 합성 과정에서 제외될 수 있습니다.

  5. 반응성 향상: 사용자의 입력에 빠르게 반응하기 위해, 컴포지터 스레드는 최소한의 변경만을 화면에 반영합니다. 이를 통해 불필요한 전체 페이지의 렌더링을 방지하고, 반응성을 향상시킵니다.

브라우저의 렌더링 작업은 주로 두 개의 스레드, 메인 스레드컴포지터 스레드에 의해 처리됩니다. 메인 스레드는 DOM 파싱, 스타일 계산, 레이아웃 작업 등을 담당하며, 컴포지터 스레드는 그래픽 관련 작업을 처리합니다. 이 두 스레드가 병렬로 작업을 수행함으로써, 웹 페이지의 렌더링 성능이 크게 향상됩니다.

래스터 스레드 (Raster Thread)란?

더 작고, 더더 작게 만들어주는 스레드 , GPU와 직접 소통을 한다!

래스터 스레드는 웹 페이지의 픽셀 데이터를 생성하는 역할을 합니다.
컴포지터 스레드가 변화를 감지하고 해당 부분의 렌더링이 필요하다고 판단하면, 래스터 스레드는 그 부분의 픽셀 데이터를 생성합니다.
레스터 스레드는 웹 브라우저의 렌더링 파이프라인 내에서 중요한 역할을 하는 스레드 중 하나입니다.

  1. 픽셀 데이터 생성: 레스터 스레드의 주요 역할은 렌더링을 위해 필요한 픽셀 데이터를 생성하는 것입니다. 특정 레이어나 객체에 대한 시각적 표현을 비트맵 형태로 생성하는 작업을 수행합니다.
  2. GPU와의 상호작용: 레스터 스레드는 그래픽 처리 장치(GPU)와 밀접하게 작동합니다. 생성된 픽셀 데이터는 GPU에 전달되어 화면에 실제로 그려지게 됩니다.
  3. 병렬 처리: 현대 브라우저는 렌더링 성능을 향상시키기 위해 여러 레스터 스레드를 동시에 실행할 수 있습니다. 이를 통해 복잡한 웹 페이지나 앱에서도 빠르게 화면을 그릴 수 있습니다.
  4. 컴포지터 스레드와의 협력: 컴포지터 스레드는 페이지 내의 변화를 감지하고, 그에 따라 어떤 부분이 다시 렌더링되어야 할지 결정합니다. 결정된 레이어나 객체들에 대한 렌더링 작업은 레스터 스레드에게 위임되어 처리됩니다.
  5. 효율성: 레스터 스레드는 필요한 부분만을 효율적으로 렌더링합니다. 예를 들어, 페이지의 특정 부분만 애니메이션이 있을 경우, 해당 부분만 레스터링 되어 성능이 향상됩니다.

2. 렌더 트리는 어떻게 만들어지는 걸까? (Render Tree)

먼저 렌더 트리에 대한 기본적인 이해가 당연히 필요합니다.

렌더 트리란 웹 페이지의 화면 렌더링을 위한 핵심 데이터 구조로, DOMCSSOM의 정보를 결합하여 화면에 어떻게 그려져야 하는지를 정의합니다.

example

아래는 현재 사용할 예시입니다. html 문서를 통해서 생성될 dom treecssom tree에 대해서 예측하고, 이를 통해서 생성될 render tree에 대해서 검증합니다.

<!DOCTYPE html>
<html>
<head>
    <style>
        body { font-family: Arial; }
        .hidden { display: none; }
        p { color: blue; }
    </style>
</head>
<body>
    <div>
        <p>Hello, World!</p>
        <span class="hidden">This is hidden.</span>
    </div>
</body>
</html>
// dom tree
html
|-- head
|   |-- style
|-- body
    |-- div
        |-- p
        |-- span (class="hidden")

HTML 문서의 구조를 나타내는 트리입니다.
headbody 요소 아래에 각각의 자식 요소들 (style, div, p, span 등)이 위치하게 됩니다.

// cssom tree
body { font-family: Arial; }
.hidden { display: none; }
p { color: blue; }

CSS 스타일 정보를 포함하고 있습니다.
예제에서는 body, .hidden,p에 대한 스타일 정보가 포함되어 있습니다.

// render tree
html
|-- body (font-family: Arial)
    |-- div
        |-- p (color: blue)

DOM 트리를 순회하면서 해당 요소에 적용되는 스타일을 CSSOM 트리에서 찾아 결합합니다.
span 요소는 display: none; 스타일을 가지고 있기 때문에 렌더 트리에서 제외됩니다.
결과적으로, p 요소만이 실제로 화면에 그려질 요소로 렌더 트리에 포함됩니다.

결과


결과는 다음과 같이 font가 Arial로 정확히 잘 들어갔으며, display: none; 속성이 들어간 span은 render tree에선 제거가 된것을 확인할 수 있습니다

3. 어떻게 배치되는거지 (Layout)

지금까지 우리는 render tree가 과연 어떻게 "구성"되는지에 대해서 학습을 진행했습니다.
하지만 render tree가 생성되어 완성된 시점에는 위치 정보가 포함 되지 않습니다. 따라서 요소의 기하학적인 속성을 찾아내는 과정이 브라우저 렌더링에 있어 아주 필수적입니다. 이때, 기하학적인 그 값을 계산하는것을 Layout 또는 Reflow라고 부릅니다.
하지만 두 용어는 살짝 차이가 존재합니다!

레이아웃(Layout)

웹 페이지가 처음 로드될 때, 브라우저는 DOM 트리CSSOM 트리를 합쳐 렌더 트리를 생성한 후, 이 렌더 트리의 각 노드에 대해 그 크기와 위치를 계산하는 과정을 "레이아웃"이라고 합니다.
이 과정에서 각 요소의 크기, 위치, 여백, 패딩 등이 결정됩니다.

리플로우 (Reflow)

웹 페이지에 이미 레이아웃이 완료된 후, 특정 요소의 크기나 위치에 변화가 생길 경우, 해당 요소와 관련된 부분의 레이아웃을 다시 계산하는 과정을 "리플로우"라고 합니다.
예를 들어, 사용자가 창 크기를 조절하거나, JavaScript를 통해 요소의 스타일을 변경할 때 리플로우가 발생할 수 있습니다.

두 과정 모두 웹 페이지의 성능에 큰 영향을 미칠 수 있습니다. 특히, 빈번한 리플로우는 웹 페이지의 반응 속도를 저하시킬 수 있기 때문에, 리플로우최소화하는 것이 중요합니다.

웹 페이지의 레이아웃을 결정하는 것은 어렵습니다. 가장 단순하게 위에서 아래로 펼쳐지는 블록 영역 하나만 있는 웹 페이지의 레이아웃을 결정할 때에도 폰트의 크기가 얼마이고 줄 바꿈을 어디서 해야하는지 고려해야 합니다. CSS 요소를 한쪽으로 흐르게 하거나, 크기를 벗어난 부분을 보이지 않게 하거나, 글이 쓰이는 방향을 정할 수 있습니다. 레이아웃 단계가 엄청난 임무를 맡고 있다는 것을 알 수 있습니다.

레이아웃 단계는 심지어 메인스레드에 많은 부하를 주기 때문에 자주 일어나지 않을수록 유저 겸험에 지극히 유리하다고 할 수 있습니다. 이를 극복하기 위한 몇가지 방법이 있습니다.

똑똑하게 렌더 트리를 배치하는 법

Dirty Bit

"더티 비트(Dirty Bit)" 체제는 렌더링 과정에서 효율적으로 리플로우와 리페인트를 관리하기 위한 시스템입니다. 이 체제는 변경이 필요한 요소만을 대상으로 렌더링 작업을 수행하도록 도와서 불필요한 연산을 줄이는 데 큰 역할을 합니다.

원리

  1. 변경 감지:웹 페이지의 요소에 어떤 변화가 발생하면 (예: 스타일 변경, 내용 추가/삭제 등), 해당 요소는 "더티(dirty)" 상태로 표시됩니다. 이 "더티" 상태는 일종의 플래그나 비트로 관리되며, 렌더링 시스템이 이를 감지하고 처리할 수 있습니다.
  2. 최적화된 렌더링: 렌더링 엔진은 더티 비트를 체크하여 변화가 감지된 요소만을 대상으로 리플로우나 리페인트를 수행합니다. 이를 통해 전체 페이지를 다시 렌더링하는 비용을 줄이고, 성능을 향상시킬 수 있습니다.

예시

HTML 요소 중에서 버튼의 색상을 변경하는 JavaScript 코드가 실행된다고 가정해봅시다.

document.getElementById('myButton').style.backgroundColor = 'red';

이 코드 실행 후, 해당 버튼 요소는 스타일 변화로 인해 "더티" 상태가 됩니다. 렌더링 엔진은 이 더티 비트를 확인하고, 해당 버튼에만 리페인트 작업을 수행하게 됩니다. 이로 인해 전체 페이지의 리페인트가 아닌, 변화된 요소만을 대상으로 최적화된 렌더링 작업이 이루어집니다.

Incremental Layout

Incremental Layout, 즉 점진 배치에 대해서 학습하기 위해선 반대 개념인 Global Layout(전역 배치)과의 비교를 통해서 학습을 진행하는 것이 좋습니다.

Global Layout(전역 배치)

전역 배치는 페이지의 모든 요소에 대해 레이아웃을 재계산하는 방식입니다.
즉, 작은 변화가 있더라도 전체 페이지의 레이아웃을 다시 계산하게 됩니다.

구현이 상당히 간단하며, 예측 또한 손쉽게 가능합니다. 하지만 치명적인 단점이 존재합니다. 작은 변화에 대해서도 전체 페이지의 레이아웃을 재계산하기 때문에 비효율적일 수 있습니다. 성능에 부담을 주며, 페이지의 반응 속도를 저하시킬 수 있습니다.

그렇다면 Incremental Layout(점진 배치)는 어떨까요?
점증 배치는 변경된 요소와 그 주변 요소에만 레이아웃을 재계산하는 방식입니다.
"더티 비트" 체제와 유사한 방식으로 작동하여, 변화가 발생한 부분만 대상으로 레이아웃을 업데이트합니다.

변화가 있는 부분만 레이아웃을 업데이트하기 때문에 효율적입니다.
전체 페이지의 레이아웃을 재계산하는 것보다 빠르게 반응할 수 있습니다.

그렇다면 진짜 어떻게 배치되는 걸까

배치 과정은 웹 페이지의 각 요소가 화면상에서 어디에 위치하며 얼마나 큰 공간을 차지할 것인지를 결정하는 핵심적인 단계입니다. 이 과정은 각 요소의 위치, 크기, 여백, 패딩 등을 계산하게 됩니다. 아래는 배치 과정의 상세한 설명과 예시를 포함한 설명입니다.

  1. 부모 렌더러의 너비 결정: 먼저, 부모 요소(렌더러)는 자신의 너비를 결정합니다. 이때 부모 요소의 너비는 상위 요소(조상)나 브라우저 창의 크기에 따라 결정될 수 있습니다.
  2. 자식 요소 검토: 부모 요소는 자식 요소들을 검토하며, 각 자식 요소에 대한 배치를 수행합니다.
  3. 자식 렌더러 배치: 부모는 각 자식 요소의 x와 y 좌표를 설정합니다. 이 좌표는 부모 요소 내에서 자식 요소가 위치할 시작점을 나타냅니다.
  4. 자식의 높이 계산: 만약 자식 요소가 더티 상태이거나, 전역 배치 상태에 있거나, 다른 이유로 높이 계산이 필요한 경우, 부모는 자식 요소의 배치를 호출하여 그 높이를 계산합니다.
  5. 부모의 높이 설정: 부모는 모든 자식 요소의 높이, 여백, 패딩을 누적하여 자신의 높이를 설정합니다. 이 값은 부모 요소의 상위 요소(부모의 부모)에서 사용될 수 있습니다.
  6. 더티 비트 플래그 제거: 배치가 완료되면 더티 비트 플래그는 제거되어, 해당 요소는 "더티" 상태가 아니라고 표시됩니다.

예시

<div style="width: 300px;">
    <p>This is a paragraph.</p>
    <img src="image.jpg" alt="An image">
</div>

여기서 <div>는 부모 요소이며, <p><img>는 자식 요소입니다.

  1. <div>의 너비는 300px로 주어졌습니다.
  2. <div>는 자식 요소인<p><img>를 검토합니다.
  3. <p>의 시작 좌표는 <div>의 상단 좌측 모서리가 됩니다.
  4. <p>의 높이는 내부의 텍스트 내용에 따라 결정됩니다.
  5. <img><p> 바로 아래에 배치되며, 해당 이미지의 높이에 따라 <div>의 전체 높이가 결정됩니다.
  6. 모든 자식 요소의 배치가 완료되면, <div>의 더티 비트 플래그가 제거됩니다.

이렇게 각 요소는 계층적으로 배치되며, 부모와 자식 간의 관계를 기반으로 레이아웃이 결정됩니다.

4. 그려질 순서를 정해보자 (Layer)

지금까지 렌더트리가 위치 정보를 가지게 되는 배치(Layout)과정에 대해서 학습을 진행했습니다.

하지만 이것으로 충분할까요? 어떤 경우에는 그려질 순서에 따라서 지극히 다른 결과가 나오기도 합니다.

https://developer.chrome.com/blog/inside-browser-part3/

그렇기 때문에 이 "순서"를 정하기 위해선 Layer 단계는 필수적입니다.
레이어는 화면에 그려지는 개별적인 그래픽 단위를 의미합니다. 웹 페이지는 다양한 요소로 구성되어 있고, 이러한 요소들은 때로는 서로 겹치거나 애니메이션 효과가 적용되기도 합니다. 레이어는 이런 요소들을 개별적으로 관리하고 렌더링하는 데 도움을 줍니다

https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_positioned_layout/Understanding_z-index 에서 css position layout에 대해서 자세히 학습을 진행할 수 있습니다

지금 하나의 예시를 통해서 레이어에 대해서 보다 직관적인 이해를 해보겠습니다.

현재 개발자 도구의 layer 탭을 사용하여 각 계층을 확인해보려고 합니다.

가장 아레 레이어인 document는 최하단의 배경에 위치하는것을 확인할 수 있습니다.

layer에 최대한 수직한 상태로 촬영을 해보았습니다.

흥미로운점은 화면에 보여지지 않은 부분에 대해서는 layer가 그려지지 않았다는 점 입니다.

5. 어떻게 그릴 수 있을까 (Paint)

지금까지 저희는 render tree 가 위치 정보까지 포함한 layout treelayer tree를 가지게 되었습니다.

그리고 이번에는 지금까지 가진 layer tree 와 layout tree를 바탕으로 페인트 레코드(paint record)를 작성할 예정입니다.

페인트 레코드는 화면에 그릴 요소의 세부 정보와 방법을 설명하는 명세입니다. 주요 구성 요소는 다음과 같습니다:

Action: 그리기 작업의 유형입니다. 예를 들어, 사각형 그리기, 텍스트 그리기 등의 작업이 있습니다.
Position: 그릴 요소의 위치와 크기를 나타냅니다. 이는 좌표 (x, y) 및 크기 (width, height)로 표현됩니다.
Styles: 요소의 스타일 정보입니다. 예를 들어, 배경색, 글꼴, 테두리 스타일 등이 포함될 수 있습니다.

페인트 레코드의 역할

명세

페인트 레코드는 화면에 그릴 요소의 세부 정보와 방법을 명세화합니다. 브라우저는 이 명세를 따라 화면에 요소를 그립니다.

순서

레이어 트리에서 결정된 순서대로 페인트 레코드 리스트(pain record list)가 생성됩니다. 이 순서는 배경부터 시작하여 사각형, 텍스트 등의 순서로 화면에 그려집니다.

6. 어떻게 나눠서 그릴 수 있을까? (Tilling)

지금까지 그릴 대상에 대한 기록(paint record)를 생성하는데 성공했습니다. 이제부터는 이 record를 어떻게 하면 더 효율적으로 그릴수 있을지 고민합니다.
타일링(Tilling)은 큰 그래픽 영역을 여러 개의 작은 조각, 즉 "타일"로 분할하는 과정을 의미합니다.
각 타일은 일반적으로 고정된 크기의 사각형 영역으로, 이렇게 분할된 작은 조각들은 개별적으로 렌더링되고 화면에 그려집니다.

타일링의 장점

  • 효율성: 전체 화면을 한 번에 렌더링하는 것보다 작은 타일 단위로 렌더링하는 것이 더 효율적입니다. 변경이 발생한 경우 해당 영역의 타일만 다시 그려질 수 있기 때문에 불필요한 렌더링 작업을 줄일 수 있습니다.

  • GPU 최적화: 현대의 그래픽 처리 장치(GPU)는 병렬 처리에 최적화되어 있습니다. 작은 타일들은 GPU에서 병렬로 빠르게 처리될 수 있습니다.

  • 메모리 사용 최적화: 큰 이미지나 그래픽 영역을 한 번에 메모리에 로드하는 것은 많은 메모리를 소모할 수 있습니다. 타일링을 사용하면 필요한 타일만 메모리에 로드되므로 메모리 사용량을 최적화할 수 있습니다.

  • 스크롤 최적화: 사용자가 페이지를 스크롤할 때, 화면의 새로운 영역에 해당하는 타일만 렌더링됩니다. 이전 영역의 타일은 재사용되거나 메모리에서 해제될 수 있습니다.

    상단에서 velog의 하단에 아직 스크롤해서 이동되지 않은 영역이 보이지 않던 이유는 타일링 되었기 때문입니다.

타일링의 단점

  • 타일 경계 문제: 타일 간의 경계에서 렌더링 이슈가 발생할 수 있습니다. 이를 해결하기 위해 약간의 오버랩이나 특별한 처리가 필요할 수 있습니다.

  • 복잡성: 타일링 시스템의 구현과 관리는 복잡해질 수 있습니다. 적절한 타일 크기, 메모리 관리, 그리고 렌더링 최적화 등 여러 요소를 고려해야 합니다.
    일반적으로 타일 크기는 256px * 256px 또는 512px * 512px입니다.

브라우저는 타일링을 사용하여 효율적인 렌더링을 달성하려고 합니다. 큰 영역을 작은 타일로 분할하여 렌더링 작업을 최적화하고, GPU의 병렬 처리 능력을 최대한 활용하여 부드러운 사용자 경험을 제공합니다.

example

현재 사진에서는 1 2 3 4 로 마킹된 타일들이 우선적으로 렌더링 됩니다.

7. 픽셀로 변환해보자 (raster)

이전까지 특정 paint recordTilling을 통해서 적절한 조각으로 나누었지만, 아직은 부족합니다. 메인스레드가 할일은 많고, 이런 큰 덩어리를 계산하고 그려내는데 에너지를 쏟을 만큼 메인 스레드는 할일이 적지 않습니다.
여기서 앞서 말했던것과 같이 raster thread를 사용하게 됩니다.

레스터 과정중에는 타일들을 일종의 비트맵 형태로 변환하여 Gpu에게 할당하여 그릴수 있도록 합니다.

프로세스를 가속화하기 위해 래스터 스레드IPC를 통해 타일을 GPU 프로세스로 보냅니다.
그런 다음 GPU 프로세스는 타일에서 비트맵을 생성하고 비트맵을 GPU 메모리에 저장합니다.

비트맵이 준비되면GPU 프로세스는 다음 단계를 위해 렌더링 프로세스의 컴포지터 스레드비트맵을 다시 전달합니다.

그리고 마지막 합성과정에 들어갈 준비를 마치게 되었습니다.

8. 모든걸 더해서 만들어보자 (Compositing)

결국 최종장에 도착했습니다!
우리는 raster과정을 통해서 타일을 통해서 GPU 프로세스에게 비트맥을 생성하도록 하고 GPU 메모리에 저장하는것까지 종료되었습니다.
그리고 컴포지터 스레드는 이러한 모든 정보들을 모아 마지막 그림을 그릴 준비를 합니다!

compositing 단계

  1. 비트맵 입력: 이 단계에서의 입력은 각 레이어에 대한 비트맵들입니다. 이 비트맵들은 앞선 페인팅 단계에서 생성되었습니다.

  2. 컴포지터 프레임 생성: 컴포지터 스레드는 입력된 비트맵들을 합성하여 하나의 컴포지터 프레임을 생성합니다.

  3. Draw Quad 명령: 모든 타일이 처리되면, 컴포지터 스레드는 브라우저 프로세스에 Draw Quad라는 명령을 전송합니다. 이 명령은 그려질 사각 영역(Quad)과 관련된 정보를 포함하고 있습니다.

  4. 브라우저 프로세스의 “viz” 컴포넌트: 브라우저 프로세스 내부에서 viz라는 컴포넌트가 Draw Quad 명령을 받습니다. 이 컴포넌트는 Display Compositor 명령을 실행하여 컴포지터 프레임을 컴퓨터 메모리에 "그립니다".

  5. 컴포지터 프레임 표시: 마지막으로, 브라우저 프로세스는 생성된 컴포지터 프레임을 브라우저에 표시합니다.

현대의 브라우저는 위의 8 단계 전체를 1/60초 내에 완료합니다. 즉, 각 단계는 평균적으로 16.67 밀리초 안에 처리되어야 합니다. 이는 브라우저의 렌더링 최적화 및 고성능 하드웨어의 발전 덕분입니다.

최종 파이프 라인

Reference

inside-browser-3
web-dev
z-index Mdn
rendering phase

10개의 댓글

comment-user-thumbnail
2023년 10월 24일

지식냠

1개의 답글
comment-user-thumbnail
2023년 10월 24일

웹페이지를 레이어로 분리해서 볼 수 있었다니.. 너무 신기합니다.ㄷㄷㄷ
정성스런 글 잘읽었습니당

1개의 답글
comment-user-thumbnail
2023년 10월 24일

덕분에 최적화에 많은 도움이 되었습니다. 다른 글도 퀄리티가 높은게 간만에 좋은 블로거를 발견하게 되어 기쁩니다!

1개의 답글
comment-user-thumbnail
2023년 10월 27일

너무 재미있게 잘 봤습니다.

1개의 답글
comment-user-thumbnail
2023년 11월 1일

우와 문과라서 궁극적으로 어떻게 적용되는지가 항상 궁금했는데 잘 봤습니다!!

1개의 답글