RenderingNG에서 주요 데이터 구조 및 구조물의 역할

Chris Harrelson
Chris Harrelson
Daniel Cheng
Daniel Cheng
Philip Rogers
Philip Rogers
Koji Ishi
Koji Ishi
Ian Kilpatrick
Ian Kilpatrick
Kyle Charbonneau
Kyle Charbonneau

이 시리즈의 이전 게시물에서는 RenderingNG 아키텍처의 목표, 주요 속성, 개략적인 구성요소를 간략하게 설명했습니다. 이제 렌더링 파이프라인의 입력과 출력인 주요 데이터 구조를 자세히 살펴보겠습니다.

이러한 데이터 구조는 다음과 같습니다.

  • 프레임 트리: 어떤 웹 문서가 어떤 렌더링 프로세스에 있는지, 어떤 Blink 렌더기에 있는지 나타내는 로컬 노드와 원격 노드로 구성됩니다.
  • 변경 불가능한 프래그먼트 트리는 레이아웃 제약 조건 알고리즘의 출력과 입력을 나타냅니다.
  • 속성 트리: 웹 문서의 변환, 클리핑, 효과, 스크롤 계층 구조를 나타내며 파이프라인 전체에 사용됩니다.
  • 디스플레이 목록 및 페인트 청크는 래스터 및 레이어화 알고리즘에 대한 입력입니다.
  • 컴포지터 프레임은 GPU를 사용하여 그리는 데 사용되는 노출 영역, 렌더링 노출 영역, GPU 텍스처 타일을 캡슐화합니다.

이러한 데이터 구조를 살펴보기 전에 이전 게시물의 데이터 구조를 기반으로 하는 간단한 예를 보여드리겠습니다. 이 게시물에서 이 예를 몇 번 사용하여 데이터 구조가 적용되는 방식을 보여줍니다.

<html>
  <div style="overflow: hidden; width: 100px; height: 100px;">
    <iframe style="filter: blur(3px);
      transform: rotateZ(1deg);
      width: 100px; height: 300px"
      id="one" src="foo.com/etc"></iframe>
  </div>
  <iframe style="top:200px;
    transform: scale(1.1) translateX(200px)"
    id="two" src="bar.com"></iframe>
</html>

프레임 트리

Chrome은 경우에 따라 상위 프레임과 다른 렌더링 프로세스에서 교차 출처 프레임을 렌더링하도록 선택할 수 있습니다.

소개의 예에는 총 3개의 프레임이 있습니다.

두 개의 iframe이 포함된 상위 프레임 foo.com

사이트 격리를 사용하면 Chromium에서 두 가지 렌더링 프로세스를 사용하여 이 웹페이지를 렌더링합니다. 각 렌더링 프로세스에는 해당 웹페이지의 프레임 트리가 자체적으로 표현되어 있습니다.

두 개의 렌더링 프로세스를 나타내는 두 개의 프레임 트리

다른 프로세스에서 렌더링된 프레임은 원격 프레임으로 표시됩니다. 예를 들어 원격 프레임은 렌더링 시 자리표시자 역할을 하는 데 필요한 최소 정보(예: 크기)를 보유합니다. 그렇지 않으면 원격 프레임에는 실제 콘텐츠를 렌더링하는 데 필요한 정보가 포함되지 않습니다.

반면에 로컬 프레임은 이전 게시물에 설명된 표준 렌더링 파이프라인을 거치게 될 프레임을 나타냅니다. 로컬 프레임에는 프레임의 데이터(예: DOM 트리 및 스타일 데이터)를 렌더링하고 표시할 수 있는 항목으로 변환하는 데 필요한 모든 정보가 포함됩니다.

렌더링 파이프라인은 로컬 프레임 트리 프래그먼트의 세부사항에 따라 작동합니다. foo.com를 기본 프레임으로 사용하는 좀 더 복잡한 예를 생각해 보세요.

<iframe src="bar.com"></iframe>

다음 bar.com 서브프레임:

<iframe src="foo.com/etc"></iframe>

아직 렌더러가 2개뿐이지만 현재 로컬 프레임 트리 프래그먼트는 3개 있으며 foo.com의 렌더링 프로세스에 2개, bar.com의 렌더링 프로세스에 1개 있습니다.

렌더 2개와 프레임 트리 프래그먼트 3개를 표현한 그림

웹페이지의 컴포지터 프레임을 하나씩 생성하기 위해 Viz는 동시에 세 개의 로컬 프레임 트리 각각 루트 프레임에서 컴포지터 프레임을 요청한 후 집계합니다. 이 게시물의 뒷부분에 나오는 컴포지터 프레임 섹션도 참고하세요.

foo.com 기본 프레임과 foo.com/other-page 서브프레임은 동일한 프레임 트리의 일부이며 동일한 프로세스에서 렌더링됩니다. 하지만 두 프레임은 서로 다른 로컬 프레임 트리 프래그먼트의 일부이므로 여전히 독립적인 문서 수명 주기를 갖습니다. 따라서 한 번의 업데이트에서 두 가지 모두에 대해 하나의 컴포지터 프레임을 생성할 수는 없습니다. 렌더링 프로세스에는 foo.com/other-page에 대해 생성된 컴포지터 프레임을 foo.com 기본 프레임의 컴포지터 프레임에 직접 합성하기에 충분한 정보가 없습니다. 예를 들어 외부 bar.com 상위 프레임은 CSS로 iframe을 변환하거나 DOM의 다른 요소로 iframe의 일부를 가리는 방식으로 foo.com/other-url iframe 표시에 영향을 미칠 수 있습니다.

시각적 속성 업데이트 폭포식 구조

기기 배율 및 표시 영역 크기와 같은 시각적 속성은 렌더링된 출력에 영향을 미치며 로컬 프레임 트리 프래그먼트 간에 동기화되어야 합니다. 각 로컬 프레임 트리 프래그먼트의 루트에는 연결된 위젯 객체가 있습니다. 시각적 속성 업데이트는 나머지 위젯으로 위에서 아래로 전파되기 전에 기본 프레임의 위젯으로 이동합니다. 예를 들어 표시 영역 크기가 변경되는 경우:

이전 텍스트에 설명된 프로세스 다이어그램

이 프로세스는 즉시 이루어지지 않으므로 복제된 시각적 속성에도 동기화 토큰이 포함됩니다. Viz 컴포지터는 이 동기화 토큰을 사용하여 모든 로컬 프레임 트리 프래그먼트가 현재 동기화 토큰으로 컴포지터 프레임을 제출할 때까지 기다립니다. 이 프로세스를 통해 컴포지터 프레임이 서로 다른 시각적 속성과 섞이지 않습니다.

변경 불가능한 프래그먼트 트리

변경할 수 없는 프래그먼트 트리는 렌더링 파이프라인의 레이아웃 단계의 출력입니다. 페이지에 있는 모든 요소의 위치와 크기를 나타냅니다(변환이 적용되지 않음).

각 트리의 프래그먼트를 표현합니다. 하나의 프래그먼트가 레이아웃이 필요한 것으로 표시됩니다.

각 프래그먼트는 DOM 요소의 일부를 나타냅니다. 일반적으로 요소당 하나의 프래그먼트만 있지만 인쇄할 때 여러 페이지로 분할되거나 다중 열 컨텍스트의 경우 열에 분할되는 경우에는 더 많은 프래그먼트가 있을 수 있습니다.

레이아웃 후에는 각 프래그먼트가 불변이 되며 다시는 변경되지 않습니다. 몇 가지 추가 제한사항이 있습니다. Google에서 하지 않는 일:

  • 트리에서 모든 '위쪽' 참조를 허용합니다. 하위 요소는 상위 요소에 대한 포인터를 가질 수 없습니다.
  • '풍선' 데이터가 트리를 따라 내려갑니다(하위 요소는 상위 요소가 아닌 하위 요소에서만 정보를 읽습니다).

이러한 제한을 통해 후속 레이아웃에 프래그먼트를 재사용할 수 있습니다. 이러한 제한이 없으면 트리 전체를 자주 재생성해야 하므로 비용이 많이 듭니다.

대부분의 레이아웃은 일반적으로 증분 업데이트입니다. 예를 들어 사용자가 요소를 클릭하는 것에 반응하여 UI의 일부를 업데이트하는 웹 앱이 있습니다. 레이아웃은 화면에서 실제로 변경된 사항에 비례하여만 작동하는 것이 이상적입니다. 이전 트리의 부분을 가능한 한 많이 재사용하면 됩니다. 이는 (일반적으로) 트리의 척추만 다시 빌드하면 된다는 것을 의미합니다.

향후 이 변경 불가능한 디자인을 통해 필요한 경우 변경 불가능한 프래그먼트 트리를 스레드 경계를 넘어 전달하거나(다른 스레드에서 후속 단계를 실행하기 위해), 원활한 레이아웃 애니메이션을 위해 여러 트리를 생성하거나, 병렬 추측 레이아웃을 실행하는 등의 흥미로운 작업을 할 수 있습니다. 또한 다중 스레딩 레이아웃 자체의 잠재력을 제공합니다.

인라인 프래그먼트 항목

인라인 콘텐츠 (주로 스타일이 지정된 텍스트)는 약간 다른 표현을 사용합니다. 상자와 포인터가 있는 트리 구조 대신 트리를 나타내는 평면 목록으로 인라인 콘텐츠를 나타냅니다. 주요 이점은 인라인의 단순 목록 표현이 빠르고 인라인 데이터 구조를 검사하거나 쿼리하는 데 유용하며 메모리 효율성이라는 것입니다. 이는 웹 렌더링 성능에 매우 중요합니다. 텍스트 렌더링은 매우 복잡하고 고도로 최적화되지 않으면 파이프라인의 가장 느린 부분이 될 수 있기 때문입니다.

흥미로운 역사적 사실로, 이는 Internet Explorer의 DOM 표현과 매우 유사합니다. Internet Explorer가 처음에 텍스트 편집기와 비슷한 방식으로 빌드되었기 때문입니다.

플랫 목록은 인라인 레이아웃 하위 트리의 깊이 우선 검색 순서대로 각 인라인 형식 지정 컨텍스트에 관해 생성됩니다. 목록의 각 항목은 (객체, 하위 요소 수)의 튜플입니다. 예를 들어 다음 DOM을 살펴보겠습니다.

<div style="width: 0;">
  <span style="color: blue; position: relative;">Hi</span> <b>there</b>.
</div>

width 속성이 0으로 설정되어 줄이 'Hi'와 'there' 사이에서 줄바꿈됩니다. 이 상황의 인라인 형식 지정 컨텍스트가 트리로 표시되면 다음과 같이 표시됩니다.

{
  "Line box": {
    "Box <span>": {
      "Text": "Hi"
    }
  },
  "Line box": {
    "Box <b>": {
      "Text": "There"
    }
  },
  {
    "Text": "."
  }
}

일반 목록은 다음과 같습니다.

  • (선 상자, 2)
  • (상자 <span>, 1)
  • (텍스트 "안녕하세요", 0)
  • (선 상자, 3)
  • (상자 <b>, 1)
  • (텍스트 'there', 0)
  • (텍스트 '.', 0)

접근성 API와 도형 API(예: getClientRects, contenteditable) 등 이 데이터 구조의 소비자가 많습니다. 제품마다 요구사항이 다릅니다. 이러한 구성요소는 편의 커서를 통해 플랫 데이터 구조에 액세스합니다.

커서에는 MoveToNext, MoveToNextLine, CursorForChildren와 같은 API가 있습니다. 이러한 커서 표현은 여러 가지 이유로 텍스트 콘텐츠에 매우 강력합니다.

  • 깊이 우선 검색 순서에서 반복하는 것은 매우 빠릅니다. 이는 캐럿 이동과 유사하기 때문에 매우 자주 사용됩니다. 플랫 목록이므로 깊이 우선 검색은 배열 오프셋만 증가시켜 빠른 반복과 메모리 지역성을 제공합니다.
  • 예를 들어 선 및 인라인 상자의 배경을 칠할 때 필요한 범위 우선 검색을 제공합니다.
  • 하위 요소의 수를 알면 다음 동위 요소로 빠르게 이동할 수 있습니다(배열 오프셋을 해당 숫자만큼 증가시키기만 하면 됨).

속성 트리

아시다시피 DOM은 요소 트리 (및 텍스트 노드)이며 CSS는 요소에 다양한 스타일을 적용할 수 있습니다.

이러한 효과는 주로 네 가지 종류로 나뉩니다.

  • Layout: 레이아웃 제약 조건 알고리즘에 입력합니다.
  • 페인트: 요소를 페인트하고 래스터하는 방법입니다(하위 요소는 아님).
  • 시각 자료: 변환, 필터, 클리핑과 같은 DOM 하위 트리에 적용된 래스터/그리기 효과
  • 스크롤: 포함된 하위 트리의 축 정렬 및 둥근 모서리 자르기 및 스크롤

속성 트리는 시각적 효과와 스크롤 효과가 DOM 요소에 적용되는 방식을 설명하는 데이터 구조입니다. 레이아웃 크기와 위치를 고려할 때 화면을 기준으로 특정 DOM 요소가 어디에 있는지와 같은 질문에 답할 수 있는 수단을 제공합니다. 그리고 시각 효과와 스크롤 효과를 적용하려면 어떤 GPU 작업 순서를 사용해야 할까요?

웹에서의 시각적 효과와 스크롤 효과는 굉장히 복잡합니다. 따라서 속성 트리가 하는 가장 중요한 작업은 이러한 복잡성을 구조의 구조와 의미를 정확하게 나타내는 단일 데이터 구조로 변환하는 동시에 DOM 및 CSS의 나머지 복잡성을 제거하는 것입니다. 이를 통해 훨씬 더 자신 있게 합성 및 스크롤 알고리즘을 구현할 수 있습니다. 구체적인 방법은 다음과 같습니다.

  • 오류가 발생하기 쉬운 도형 및 기타 계산을 한곳에 집중시킬 수 있습니다.
  • 속성 트리 빌드 및 업데이트의 복잡성은 하나의 렌더링 파이프라인 단계로 격리됩니다.
  • 전체 DOM 상태보다 다양한 스레드와 프로세스로 속성 트리를 보내는 것이 훨씬 쉽고 빠르기 때문에 많은 사용 사례에 사용할 수 있습니다.
  • 사용 사례가 많을수록 위에 빌드된 도형 캐싱이 서로의 캐시를 재사용할 수 있으므로 더 많은 이점을 얻을 수 있습니다.

RenderingNG는 다음을 비롯한 다양한 용도로 속성 트리를 사용합니다.

  • 페인트에서 합성 및 기본 스레드에서 합성 분리
  • 최적의 합성 / 그리기 전략 결정
  • IntersectionObserver 도형 측정
  • 오프스크린 요소 및 GPU 텍스처 타일 작업 방지
  • 페인트와 래스터를 효율적이고 정확하게 무효화합니다.
  • 코어 웹 바이탈에서 레이아웃 변경최대 콘텐츠 페인트 측정

모든 웹 문서에는 변환, 클립, 효과, 스크롤이라는 4개의 개별 속성 트리가 있습니다.(*) 변환 트리는 CSS 변환 및 스크롤을 나타냅니다. 스크롤 변환은 2D 변환 행렬로 표현됩니다. 클립 트리는 오버플로 클립을 나타냅니다. 효과 트리는 불투명도, 필터, 마스크, 혼합 모드, 다른 종류의 클립(예: 클립 경로) 등 다른 모든 시각 효과를 나타냅니다. 스크롤 트리는 체인을 함께 스크롤하는 방법과 같은 스크롤 관련 정보를 나타냅니다. 컴포지터 스레드에서 스크롤을 실행하는 데 필요합니다. 속성 트리의 각 노드는 DOM 요소가 적용한 스크롤 또는 시각 효과를 나타냅니다. 여러 효과가 있는 경우 같은 요소의 각 트리에 두 개 이상의 속성 트리 노드가 있을 수 있습니다.

각 트리의 토폴로지는 DOM의 희소 표현과 같습니다. 예를 들어 오버플로 클립이 있는 DOM 요소가 3개 있는 경우 클립 트리 노드가 3개 있으며 클립 트리의 구조는 오버플로 클립 간의 포함 블록 관계를 따릅니다. 나무 사이에는 링크도 있습니다. 이러한 링크는 노드의 상대적 DOM 계층 구조 및 적용 순서를 나타냅니다. 예를 들어 DOM 요소의 변환이 필터가 있는 다른 DOM 요소 아래에 있으면 물론 변환은 필터보다 먼저 적용됩니다.

각 DOM 요소에는 해당 요소에 적용되는 가장 가까운 상위 클립, 변환, 효과 트리 노드를 나타내는 4-튜플 (변환, 클립, 효과, 스크롤)인 속성 트리 상태가 있습니다. 이 정보를 사용하면 요소에 적용되는 클립, 변환, 효과의 목록과 순서를 정확히 알 수 있으므로 매우 편리합니다. 이를 통해 화면에서 어디에 위치하며 어떻게 그리는지 알 수 있습니다.

(출처)

<html>
  <div style="overflow: scroll; width: 100px; height: 100px;">
    <iframe style="filter: blur(3px);
      transform: rotateZ(1deg);
      width: 100px; height: 300px"
  id="one" srcdoc="iframe one"></iframe>
  </div>
  <iframe style="top:200px;
      transform: scale(1.1) translateX(200px)" id=two
      srcdoc="iframe two"></iframe>
</html>

앞의 예와 약간 다른 이전 예의 경우 생성된 속성 트리의 핵심 요소는 다음과 같습니다.

속성 트리의 다양한 요소 예

목록 및 페인트 청크 표시

표시 항목에는 Skia로 래스터화할 수 있는 하위 수준 그리기 명령어 (여기 참고)가 포함되어 있습니다. 표시 항목은 일반적으로 테두리나 배경 그리기와 같은 몇 가지 그리기 명령어만으로 간단합니다. 페인트 트리 걷기는 CSS 페인팅 순서에 따라 레이아웃 트리와 연결된 프래그먼트를 반복하여 표시 항목 목록을 생성합니다.

예를 들면 다음과 같습니다.

초록색 직사각형 안에 &#39;Hello world&#39;라는 단어가 있는 파란색 상자

<div id="green" style="background:green; width:80px;">
    Hello world
</div>
<div id="blue" style="width:100px;
  height:100px; background:blue;
  position:absolute;
  top:0; left:0; z-index:-1;">
</div>

이 HTML 및 CSS는 다음과 같은 표시 목록을 생성합니다. 여기서 각 셀은 표시 항목입니다.

뷰의 배경 #blue 배경 #green 배경 #green 인라인 텍스트
크기가 800x600이고 흰색인 drawRect 위치 0,0에 크기가 100x100이고 파란색인 drawRect 위치 8,8에 크기가 80x18이고 녹색인 drawRect 위치 8,8에 'Hello world' 텍스트가 있는 drawTextBlob

표시 항목 목록은 맨순으로 정렬됩니다. 위 예에서 녹색 div는 DOM 순서의 파란색 div 앞에 있지만 CSS 페인트 순서에서는 음의 Z-색인 파란색 div가 녹색 div (4.1단계)보다 먼저(3단계) 페인팅해야 합니다. 표시 항목은 CSS 페인트 순서 사양의 원자적 단계와 대략적으로 일치합니다. 하나의 DOM 요소로 여러 개의 표시 항목이 생성될 수 있습니다. 예를 들어 #green에 배경에 대한 표시 항목과 인라인 텍스트에 대한 다른 표시 항목이 있습니다. 이 세부사항은 음수 여백으로 생성된 인터리브 처리와 같은 CSS 페인트 순서 사양의 전체 복잡성을 나타내는 데 중요합니다.

회색 상자와 &#39;Hello world&#39; 문구가 표시된 초록색 직사각형

<div id="green" style="background:green; width:80px;">
    Hello world
</div>
<div id="gray" style="width:35px; height:20px;
  background:gray;margin-top:-10px;"></div>

이렇게 하면 다음과 같은 표시 목록이 생성되며, 여기서 각 셀은 표시 항목입니다.

뷰의 배경 #green 배경 #gray 배경 #green 인라인 텍스트
크기가 800x600이고 흰색인 drawRect 위치 8,8에 크기가 80x18이고 녹색인 drawRect 위치 8,16에 크기가 35x20이고 회색인 drawRect 위치 8,8에 'Hello world' 텍스트가 있는 drawTextBlob

표시 항목 목록은 나중에 업데이트에서 저장되고 재사용됩니다. 페인트 트리 워크 중에 레이아웃 객체가 변경되지 않았다면 표시 항목이 이전 목록에서 복사됩니다. 추가적인 최적화는 CSS 페인트 순서 사양의 속성, 즉 컨텍스트 페인트를 원자적으로 쌓는 데 사용됩니다. 스태킹 컨텍스트 내에서 레이아웃 객체가 변경되지 않은 경우 페인트 트리 워크는 스태킹 컨텍스트를 건너뛰고 이전 목록의 전체 디스플레이 항목 시퀀스를 복사합니다.

현재 속성 트리 상태는 페인트 트리 걷기 중에 유지되며 표시 항목 목록은 동일한 속성 트리 상태를 공유하는 디스플레이 항목의 '청크'로 그룹화됩니다. 예를 들면 다음과 같습니다.

분홍색 상자와 주황색 상자가 기울어져 있습니다.

<div id="scroll" style="background:pink; width:100px;
   height:100px; overflow:scroll;
   position:absolute; top:0; left:0;">
    Hello world
    <div id="orange" style="width:75px; height:200px;
      background:orange; transform:rotateZ(25deg);">
        I'm falling
    </div>
</div>

이렇게 하면 다음과 같은 표시 목록이 생성되며, 여기서 각 셀은 표시 항목입니다.

뷰의 배경 #scroll 배경 #scroll 인라인 텍스트 #orange 배경 #orange 인라인 텍스트
크기가 800x600이고 흰색인 drawRect 위치 0,0에 크기가 100x100이고 분홍색인 drawRect 위치 0,0 및 'Hello world' 텍스트가 있는 drawTextBlob 위치 0,0에 크기가 75x200이고 주황색인 drawRect 위치 0,0 및 'I'm Faing' 텍스트가 있는 drawTextBlob

그러면 변환 속성 트리와 페인트 청크가 다음과 같이 변경됩니다 (간결성을 위해 단순화됨).

청크 1의 첫 번째 두 셀, 청크 2의 세 번째 셀, 청크 3의 마지막 두 셀인 위 테이블의 이미지입니다.

정렬된 페인트 청크 목록은 디스플레이 항목 및 속성 트리 상태의 그룹으로, 렌더링 파이프라인의 계층화 단계에 대한 입력입니다. 전체 페인트 청크 목록을 단일 합성 레이어로 병합하여 함께 래스터화할 수 있지만 이 경우 사용자가 스크롤할 때마다 비용이 많이 드는 래스터화가 필요합니다. 각 페인트 청크에 합성된 레이어를 생성하고 개별적으로 래스터화하여 모든 재래스터화를 방지할 수 있지만, 이렇게 하면 GPU 메모리가 빠르게 소진됩니다. 계층화 단계에서는 GPU 메모리 간에 균형을 맞추고 상황이 변경될 때 비용을 줄여야 합니다. 일반적으로 좋은 방법은 기본적으로 청크를 병합하고 컴포지터 스레드 스크롤 또는 컴포지터 스레드 변환 애니메이션과 같이 컴포지터 스레드에서 변경될 것으로 예상되는 속성 트리 상태를 가진 페인트 청크는 병합하지 않는 것입니다.

앞의 예에서는 합성된 레이어 두 개를 생성하는 것이 좋습니다.

  • 그리기 명령어가 포함된 800x600 합성 레이어:
    1. drawRect(크기 800x600, 흰색)
    2. 위치 0,0에 크기가 100x100이고 분홍색인 drawRect
  • 그리기 명령어가 포함된 144x224 합성 레이어:
    1. 위치 0,0 및 'Hello world' 텍스트가 있는 drawTextBlob
    2. 번역 0,18
    3. rotateZ(25deg)
    4. 위치 0,0에 크기가 75x200이고 주황색인 drawRect
    5. 위치 0,0 및 '낙하 중' 텍스트가 있는 drawTextBlob

사용자가 #scroll를 스크롤하면 두 번째 합성된 레이어가 이동하지만 래스터화는 필요하지 않습니다.

여기에 있는 예시에는 속성 트리에 관한 이전 섹션의 페인트 청크가 6개 있습니다. 속성 트리 상태 (변환, 클립, 효과, 스크롤)와 함께 다음 특성을 갖습니다.

  • 문서 배경: 문서 스크롤, 문서 클립, 루트, 문서 스크롤
  • div (별도의 페인트 청크 3개): 문서 스크롤, 문서 클립, #one 블러, 문서 스크롤
  • iframe #one: #one 회전, 오버플로 스크롤 클립, #one 흐리게 처리, div 스크롤
  • iframe #two: #two 배율, 문서 클립, 루트, 문서 스크롤

컴포지터 프레임: 노출 영역, 렌더링 노출 영역, GPU 텍스처 타일

이전 게시물 (여기)에서 설명했듯이 브라우저 및 렌더링 프로세스는 콘텐츠의 래스터화를 관리하고 컴포지터 프레임을 Viz 프로세스에 제출하여 화면에 표시합니다. 컴포지터 프레임은 RenderingNG가 래스터화된 콘텐츠를 함께 연결하고 GPU를 사용하여 효율적으로 그리는 방법을 나타내는 방법입니다.

카드

이론적으로 렌더링 프로세스나 브라우저 프로세스 컴포지터는 픽셀을 렌더기 표시 영역의 전체 크기인 단일 텍스처로 래스터화하고 해당 텍스처를 Viz에 제출할 수 있습니다. 디스플레이 컴포지터는 단일 텍스처의 픽셀을 프레임 버퍼의 적절한 위치(예: 화면)에 복사하기만 하면 됩니다. 그러나 이 컴포지터가 단일 픽셀도 업데이트하려면 전체 표시 영역을 다시 래스터화하고 Viz에 새 텍스처를 제출해야 합니다.

대신 표시 영역이 타일로 나뉩니다. 별도의 GPU 텍스처 타일은 표시 영역의 일부에 대해 래스터화된 픽셀로 각 타일을 백업합니다. 그러면 렌더기가 개별 타일을 업데이트하거나 기존 타일의 화면 위치만 변경할 수도 있습니다. 예를 들어 웹사이트를 스크롤할 때 기존 타일의 위치가 위로 이동하므로 페이지 아래쪽에 있는 콘텐츠를 위해 새 카드를 래스터화해야 하는 경우가 있습니다.

타일 4개

위의 이미지는 화창한 날의 이미지이며 4개의 타일이 있습니다. 스크롤이 되면 다섯 번째 타일이 나타나기 시작합니다. 타일 중 하나는 단 하나의 색상 (하늘색)만 있고 상단에는 동영상과 iframe이 있습니다. 자, 이제 다음 주제로 넘어가겠습니다.

쿼드 및 표면

GPU 텍스처 타일은 특별한 종류의 쿼드로, 텍스처의 한 카테고리나 다른 카테고리를 나타내는 멋진 이름일 뿐입니다. 쿼드는 입력 텍스처를 식별하고 변환 및 시각 효과를 적용하는 방법을 나타냅니다. 예를 들어 일반 콘텐츠 타일에는 타일 그리드에서의 x, y 위치를 나타내는 변환이 포함됩니다.

GPU 텍스처 타일

래스터화된 타일은 쿼드 목록인 렌더링 패스에 래핑됩니다. 렌더 패스에는 픽셀 정보가 없습니다. 대신, 원하는 픽셀 출력을 생성하기 위해 각 쿼드를 그리는 위치와 방법에 관한 지침이 있습니다. 각 GPU 텍스처 타일에는 그리기 쿼드가 있습니다. 디스플레이 컴포지터는 쿼드 목록을 반복하면서 지정된 시각적 효과로 각 쿼드를 그려서 렌더 패스에 필요한 픽셀 출력을 생성하기만 하면 됩니다. 렌더 패스를 위한 그리기 쿼드를 합성하는 작업은 GPU에서 효율적으로 실행될 수 있습니다. 허용되는 시각 효과는 GPU 기능에 직접 매핑되는 시각 효과가 신중하게 선택되기 때문입니다.

래스터화된 타일 외에 추가 유형의 그리기 쿼드가 있습니다. 예를 들어 텍스처로 전혀 백업되지 않는 단색 그리기 쿼드가 있으며, 동영상이나 캔버스와 같이 타일이 아닌 텍스처에는 텍스처 그리기 쿼드가 있습니다.

또한 컴포지터 프레임이 다른 컴포지터 프레임을 삽입할 수도 있습니다. 예를 들어 브라우저 컴포지터는 브라우저 UI가 있는 컴포지터 프레임과 렌더링 컴포지터 콘텐츠가 삽입될 빈 직사각형을 생성합니다. 또 다른 예는 사이트 격리 iframe입니다. 이러한 삽입은 노출 영역을 통해 수행됩니다.

컴포지터가 컴포지터 프레임을 제출하면 표면 ID라고 하는 식별자가 함께 제공되므로 다른 컴포지터 프레임이 참조를 통해 삽입할 수 있습니다. 특정 노출 영역 ID와 함께 제출된 최신 컴포지터 프레임은 Viz에 의해 저장됩니다. 그러면 다른 컴포지터 프레임이 나중에 표면 그리기 쿼드를 통해 이 프레임을 참조할 수 있으므로 Viz는 그릴 내용을 알고 있습니다. 표면 그리기 쿼드에는 표면 ID만 포함되며 텍스처는 포함되지 않습니다.

중간 렌더 패스

다수의 필터 또는 고급 혼합 모드와 같은 일부 시각 효과를 사용하려면 중간 텍스처에 2개 이상의 쿼드를 그려야 합니다. 그런 다음 중간 텍스처를 GPU의 대상 버퍼 (또는 다른 중간 텍스처)에 그려 동시에 시각적 효과를 적용합니다. 이를 허용하기 위해 컴포지터 프레임에는 실제로 렌더 패스 목록이 포함됩니다. 항상 루트 렌더 패스가 있는데, 이 렌더 패스는 가장 마지막에 그려지고 그 대상이 프레임 버퍼에 상응하며, 더 많은 패스가 있을 수 있습니다.

렌더 패스가 여러 개 있을 수 있다는 점에서 '렌더 패스'라는 이름이 설명되어 있습니다. 각 패스는 GPU에서 여러 '패스'로 순차적으로 실행되어야 하는 반면, 단일 패스는 하나의 대규모 병렬 GPU 계산으로 완료될 수 있습니다.

집계

여러 컴포지터 프레임이 Viz에 제출되며 화면에 함께 그려야 합니다. 이 작업은 데이터를 집계된 단일 컴포지터 프레임으로 변환하는 집계 단계로 실행됩니다. 집계는 표면 그리기 쿼드를 지정된 컴포지터 프레임으로 대체합니다. 불필요한 중간 텍스처나 화면에 표시되지 않는 콘텐츠를 최적화할 수도 있습니다. 예를 들어 대부분의 경우 사이트에서 격리된 iframe의 컴포지터 프레임에는 자체 중간 텍스처가 필요하지 않으며 적절한 그리기 쿼드를 통해 프레임 버퍼에 직접 그릴 수 있습니다. 집계 단계에서는 이러한 최적화를 파악하고 개별 렌더링 컴포지터가 액세스할 수 없는 전역 지식을 기반으로 이를 적용합니다.

다음은 이 게시물의 시작 부분부터 예시를 나타내는 실제 컴포지터 프레임입니다.

  • foo.com/index.html 표면: id=0
    • 렌더링 패스 0: 출력에 그립니다.
      • 렌더 패스 그리기 쿼드: 3px 블러로 그리고 렌더 패스 0으로 클립합니다.
        • 렌더링 패스 1:
          • #one iframe의 카드 콘텐츠에 관한 쿼드를 그립니다(각각 x 및 y 위치).
      • 표면 그리기 쿼드: ID 2, scale 및 translate 변환으로 그려짐
  • 브라우저 UI 노출 영역: ID=1
    • 렌더링 패스 0: 출력에 그립니다.
      • 브라우저 UI용 쿼드 그리기 (타일식도)
  • bar.com/index.html 표면: ID=2
    • 렌더링 패스 0: 출력에 그립니다.
      • #two iframe 콘텐츠의 쿼드를 그립니다(각 콘텐츠의 x 및 y 위치).

결론

읽어주셔서 감사합니다. 이전 게시물 2개와 함께 RenderingNG 개요를 마무리합니다. 다음으로 렌더링 파이프라인의 여러 하위 구성요소에서 발생하는 과제와 기술을 처음부터 끝까지 심층적으로 살펴봅니다. 곧 지원될 예정입니다.

삽화: 우나 크라베츠