Các cấu trúc dữ liệu chính và vai trò của các cấu trúc này trong 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

Các bài đăng trước trong loạt bài này đã cung cấp thông tin tổng quan về mục tiêu, thuộc tính chínhcác thành phần cấp cao của kiến trúc RenderingNG. Bây giờ, hãy tìm hiểu các cấu trúc dữ liệu chính là dữ liệu đầu vào và đầu ra cho quy trình kết xuất.

Có những cấu trúc dữ liệu sau:

  • Cây khung, bao gồm các nút cục bộ và nút từ xa đại diện cho tài liệu web nào đang có quy trình kết xuất nào và trình kết xuất Blink nào.
  • Cây mảnh bất biến, đại diện cho đầu ra của (và đầu vào vào) thuật toán ràng buộc bố cục.
  • Cây thuộc tính đại diện cho hệ phân cấp biến đổi, cắt, hiệu ứng và cuộn của tài liệu web và được sử dụng trong suốt quy trình.
  • Danh sách hiển thị và đoạn vẽ là dữ liệu đầu vào cho thuật toán đường quét và phân lớp.
  • Khung kết hợp đóng gói các bề mặt, giao diện kết xuất và ô hoạ tiết GPU dùng để vẽ bằng GPU.

Trước khi tìm hiểu các cấu trúc dữ liệu này, tôi muốn đưa ra ví dụ đơn giản sau đây về những gì được xây dựng dựa trên một cấu trúc từ bài đăng trước. Tôi sẽ sử dụng ví dụ này một vài lần trong bài đăng này, cho thấy cách cấu trúc dữ liệu áp dụng cho nó.

<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>

Cây khung

Đôi khi, Chrome có thể chọn hiển thị một khung trên nhiều nguồn gốc trong một quy trình kết xuất khác với khung mẹ.

Trong ví dụ giới thiệu, có tổng cộng 3 khung:

Khung mẹ foo.com, chứa hai iframe.

Với tính năng tách biệt trang web, Chromium sẽ sử dụng hai quy trình kết xuất để kết xuất trang web này. Mỗi quy trình kết xuất đều có phần đại diện riêng của cây khung cho trang web đó:

Hai cây khung đại diện cho hai quá trình kết xuất.

Một khung hình kết xuất trong một quy trình khác được biểu thị dưới dạng khung từ xa. Khung từ xa chứa thông tin tối thiểu cần thiết để hoạt động như một phần giữ chỗ trong quá trình kết xuất, chẳng hạn như kích thước. Nếu không, khung từ xa không chứa bất kỳ thông tin nào cần để hiển thị nội dung thực tế.

Ngược lại, khung cục bộ đại diện cho một khung sẽ đi qua quy trình kết xuất chuẩn như mô tả trong các bài đăng trước. Khung cục bộ chứa tất cả thông tin cần thiết để biến dữ liệu cho khung đó (chẳng hạn như dữ liệu kiểu và cây DOM) thành nội dung có thể kết xuất và hiển thị được.

Quy trình kết xuất hoạt động dựa trên độ chi tiết của một mảnh cây khung cục bộ. Hãy xem xét một ví dụ phức tạp hơn với foo.com là khung chính:

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

Và khung phụ bar.com sau đây:

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

Mặc dù vẫn chỉ có hai trình kết xuất, nhưng hiện có 3 mảnh cây khung cục bộ, với 2 mảnh trong quá trình kết xuất foo.com và 1 mảnh trong quá trình kết xuất bar.com:

Biểu thị hai kết xuất và ba mảnh cây khung.

Để tạo một khung trình tổng hợp cho trang web, Viz yêu cầu đồng thời một khung trình tổng hợp từ khung gốc của mỗi trong số 3 cây khung cục bộ, sau đó tổng hợp chúng. (Đồng thời xem phần khung trình tổng hợp ở phần sau trong bài đăng này.)

Khung chính foo.com và khung phụ foo.com/other-page là một phần của cùng một cây khung và được kết xuất trong cùng một quy trình. Tuy nhiên, 2 khung này vẫn có vòng đời tài liệu độc lập vì chúng thuộc các mảnh cây khung cục bộ khác nhau. Vì lý do này, bạn không thể tạo một khung trình tổng hợp cho cả hai trong một bản cập nhật. Quá trình kết xuất không có đủ thông tin để kết hợp trực tiếp khung trình tổng hợp được tạo cho foo.com/other-page vào khung trình tổng hợp cho khung chính foo.com. Ví dụ: khung mẹ bar.com ngoài quy trình có thể ảnh hưởng đến việc hiển thị iframe foo.com/other-url, bằng cách chuyển đổi iframe bằng CSS hoặc ẩn các phần của iframe bằng các phần tử khác trong DOM.

Thác nước cập nhật thuộc tính hình ảnh

Các thuộc tính hình ảnh như hệ số tỷ lệ thiết bị và kích thước khung nhìn ảnh hưởng đến kết quả được kết xuất, đồng thời phải được đồng bộ hoá giữa các mảnh cây khung cục bộ. Gốc của mỗi mảnh cây khung cục bộ có một đối tượng tiện ích liên kết với mảnh đó. Bản cập nhật thuộc tính hình ảnh sẽ chuyển đến tiện ích của khung chính trước khi áp dụng cho các tiện ích còn lại từ trên xuống dưới. Ví dụ: khi kích thước khung nhìn thay đổi:

Sơ đồ quy trình được giải thích trong nội dung trước.

Quá trình này không diễn ra ngay lập tức, vì vậy, các thuộc tính hình ảnh được sao chép cũng bao gồm mã thông báo đồng bộ hoá. Trình tổng hợp Viz sử dụng mã thông báo đồng bộ hoá này để chờ tất cả các mảnh cây khung cục bộ gửi một khung trình tổng hợp với mã thông báo đồng bộ hoá hiện tại. Quá trình này giúp tránh kết hợp các khung tổng hợp với các thuộc tính hình ảnh khác nhau.

Cây mảnh bất biến

Cây mảnh bất biến là kết quả đầu ra của giai đoạn bố cục của quy trình kết xuất. Thuộc tính này thể hiện vị trí và kích thước của tất cả phần tử trên trang (không áp dụng phép biến đổi).

Phần hiển thị của các mảnh trong mỗi cây, trong đó một mảnh được đánh dấu là cần bố cục.

Mỗi mảnh đại diện cho một phần của một phần tử DOM. Thường thì mỗi phần tử chỉ có một mảnh cho mỗi phần tử, nhưng có thể có nhiều hơn nếu mảnh được chia trên nhiều trang khi in hoặc khi ở chế độ nhiều cột.

Sau bố cục, mỗi mảnh sẽ không thể thay đổi được và không bao giờ thay đổi nữa. Điều quan trọng là chúng tôi cũng đặt ra một số quy định hạn chế bổ sung. Chúng tôi không:

  • Cho phép mọi tham chiếu "lên" trong cây. (Phần tử con không thể chứa con trỏ tới phần tử mẹ.)
  • dữ liệu "bong bóng trò chuyện" ở dưới cây (thành phần con chỉ đọc thông tin từ thành phần con của nó chứ không phải từ thành phần mẹ).

Những hạn chế này cho phép chúng ta sử dụng lại một mảnh cho bố cục tiếp theo. Nếu không có những hạn chế này, chúng tôi thường cần tạo lại toàn bộ cây. Việc này khá tốn kém.

Hầu hết các bố cục thường là các bản cập nhật gia tăng, ví dụ: một ứng dụng web cập nhật một phần nhỏ của giao diện người dùng để phản hồi việc người dùng nhấp vào một phần tử. Tốt nhất là bố cục chỉ nên hoạt động theo tỷ lệ thuận với những gì thực sự thay đổi trên màn hình. Chúng ta có thể đạt được điều này bằng cách sử dụng lại nhiều phần của cây trước đó nhất có thể. Điều này có nghĩa là (thông thường), chúng ta chỉ cần dựng lại thân cây.

Trong tương lai, thiết kế bất biến này sẽ cho phép chúng ta làm những việc thú vị như truyền cây mảnh bất biến qua ranh giới luồng nếu cần (để thực hiện các giai đoạn tiếp theo trên một luồng khác), tạo nhiều cây cho ảnh động có bố cục mượt mà hoặc thực hiện bố cục suy đoán song song. Điều này cũng mang đến cho chúng ta tiềm năng của chính bố cục đa luồng.

Mục mảnh cùng dòng

Nội dung cùng dòng (chủ yếu là văn bản có kiểu) sử dụng cách trình bày hơi khác. Thay vì cấu trúc cây có các hộp và con trỏ, chúng tôi biểu thị nội dung cùng dòng trong một danh sách phẳng tượng trưng cho cây. Lợi ích chính là việc biểu diễn danh sách phẳng cho nội tuyến rất nhanh, hữu ích khi kiểm tra hoặc truy vấn cấu trúc dữ liệu cùng dòng, đồng thời hiệu quả về bộ nhớ. Điều này cực kỳ quan trọng đối với hiệu suất kết xuất web, vì việc kết xuất văn bản rất phức tạp và có thể dễ dàng trở thành phần chậm nhất của quy trình, trừ phi được tối ưu hoá cao.

Xin lưu ý rằng cách này rất giống với cách Internet Explorer trước đây biểu thị DOM vì ban đầu, dịch vụ này được xây dựng theo cách tương tự như một trình chỉnh sửa văn bản.

Danh sách phẳng được tạo cho mỗi ngữ cảnh định dạng cùng dòng theo thứ tự tìm kiếm chiều sâu của cây con bố cục cùng dòng. Mỗi mục trong danh sách là một bộ dữ liệu gồm (đối tượng, số lượng phần tử con). Ví dụ: hãy xem xét DOM này:

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

(Lưu ý rằng thuộc tính width được đặt thành 0 để dòng bao bọc giữa "Hi" (Xin chào) và "here.") Khi ngữ cảnh định dạng cùng dòng cho trường hợp này được biểu thị dưới dạng cây, hệ thống sẽ thể hiện như sau:

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

Danh sách phẳng sẽ có dạng như sau:

  • (Hộp dòng, 2)
  • (Hộp <span>, 1)
  • (Văn bản "Xin chào", 0)
  • (Hộp dòng, 3)
  • (Hộp <b>, 1)
  • (Văn bản "ở đó", 0)
  • (Văn bản ".", 0)

Có nhiều đối tượng sử dụng cấu trúc dữ liệu này: API hỗ trợ tiếp cận và API hình học, chẳng hạn như getClientRectscontentedit. Mỗi loại có các yêu cầu khác nhau. Các thành phần này truy cập cấu trúc dữ liệu phẳng thông qua một con trỏ tiện lợi.

Con trỏ có các API như MoveToNext, MoveToNextLine, CursorForChildren. Cách biểu diễn con trỏ này rất hiệu quả đối với nội dung văn bản vì nhiều lý do:

  • Lặp lại theo thứ tự tìm kiếm theo chiều sâu theo thứ tự rất nhanh. Phương thức này được sử dụng rất thường xuyên vì tương tự như chuyển động của con nháy. Vì đây là danh sách phẳng, nên tính năng tìm kiếm theo chiều sâu chỉ làm tăng độ lệch mảng, cung cấp khả năng lặp lại nhanh và vị trí của bộ nhớ.
  • Tính năng này cung cấp chức năng tìm kiếm theo chiều rộng, cần thiết khi vẽ nền của các dòng và hộp cùng dòng.
  • Khi biết số lượng thành phần con cháu, việc di chuyển đến phiên bản đồng cấp tiếp theo (chỉ cần tăng độ lệch mảng theo số đó).

Cây tài sản

Như bạn đã biết, DOM là một cây phần tử (cộng thêm nút văn bản) và CSS có thể áp dụng nhiều kiểu cho các phần tử.

Những yếu tố này chủ yếu có 4 kiểu hiệu ứng:

  • Layout (Bố cục): dữ liệu đầu vào cho thuật toán ràng buộc bố cục.
  • Paint: cách vẽ và đường quét phần tử (nhưng không phải các thành phần con cháu của nó).
  • Hình ảnh: hiệu ứng đường quét/vẽ được áp dụng cho cây con DOM, chẳng hạn như biến đổi, bộ lọc và cắt.
  • Cuộn: cắt các góc tròn và căn chỉnh theo trục và cuộn của cây con chứa trong đó.

Cây tài sản là cấu trúc dữ liệu giải thích cách áp dụng hiệu ứng hình ảnh và hiệu ứng cuộn cho các phần tử DOM. Phần tử này cung cấp phương tiện để trả lời các câu hỏi như: ở đâu, so với màn hình, là một phần tử DOM nhất định, dựa trên kích thước và vị trí bố cục của phần tử đó? Và: nên sử dụng trình tự thao tác GPU nào để áp dụng hiệu ứng hình ảnh và hiệu ứng cuộn?

Hiệu ứng hình ảnh và hiệu ứng cuộn trên web rất phức tạp với sự huy hoàng của chúng. Vì vậy, điều quan trọng nhất của cây thuộc tính là chuyển sự phức tạp đó thành một cấu trúc dữ liệu duy nhất thể hiện chính xác cấu trúc và ý nghĩa của chúng, đồng thời loại bỏ phần còn lại của DOM và CSS. Điều này cho phép chúng tôi triển khai thuật toán kết hợp và cuộn với độ tin cậy cao hơn nhiều. Cụ thể:

  • Hình học có thể dễ xảy ra lỗi và các phép tính khác có thể được tập trung ở cùng một nơi.
  • Sự phức tạp của việc xây dựng và cập nhật cây thuộc tính được tách riêng thành một giai đoạn quy trình kết xuất.
  • Việc gửi cây thuộc tính đến các luồng và quy trình khác nhau dễ dàng và nhanh hơn nhiều so với trạng thái DOM đầy đủ, do đó, bạn có thể sử dụng các cây thuộc tính này cho nhiều trường hợp sử dụng.
  • Càng có nhiều trường hợp sử dụng, chúng tôi càng thu được nhiều lợi ích từ chức năng lưu hình học vào bộ nhớ đệm được tích hợp sẵn từ trước, vì chúng có thể sử dụng lại bộ nhớ đệm của nhau.

RenderingNG sử dụng cây thuộc tính cho nhiều mục đích, bao gồm:

  • Tách việc kết hợp khỏi sơn và kết hợp khỏi luồng chính.
  • Xác định chiến lược kết hợp / vẽ tối ưu.
  • Đo lường hình học IntersectionObserver.
  • Tránh sử dụng cho các phần tử ngoài màn hình và ô kết cấu GPU.
  • Vô hiệu hoá hiệu quả và chính xác sơn và đường quét.
  • Đo lường mức độ thay đổi bố cụcnội dung lớn nhất hiển thị trong Các chỉ số quan trọng về trang web.

Mỗi tài liệu web có 4 cây thuộc tính riêng biệt: biến đổi, cắt, hiệu ứng và cuộn.(*) Cây biến đổi đại diện cho các phép biến đổi CSS và cuộn. (Phép biến đổi cuộn được biểu thị dưới dạng ma trận biến đổi 2D.) Cây clip đại diện cho các đoạn video bị tràn (overflow clips). Cây hiệu ứng đại diện cho tất cả các hiệu ứng hình ảnh khác: độ mờ, bộ lọc, mặt nạ, chế độ kết hợp và các loại đoạn video khác như đường dẫn đoạn video. Cây cuộn biểu thị thông tin về thao tác cuộn, chẳng hạn như cách cuộn chuỗi lại với nhau; cần thực hiện thao tác cuộn trên luồng của trình tổng hợp. Mỗi nút trong cây thuộc tính đại diện cho hiệu ứng cuộn hoặc hình ảnh được phần tử DOM áp dụng. Nếu có nhiều hiệu ứng, có thể có nhiều nút cây thuộc tính trong mỗi cây cho cùng một phần tử.

Cấu trúc liên kết của mỗi cây giống như một bản trình bày thưa của DOM. Ví dụ: nếu có 3 phần tử DOM có các đoạn cắt tràn, thì sẽ có 3 nút cây cắt và cấu trúc của cây đoạn cắt sẽ tuân theo mối quan hệ khối chứa giữa các đoạn chứa mục bổ sung. Ngoài ra còn có những đường liên kết giữa các cây. Các đường liên kết này cho biết hệ phân cấp DOM tương đối và theo đó, thứ tự áp dụng của các nút. Ví dụ: nếu phép biến đổi trên một phần tử DOM nằm dưới một phần tử DOM khác có bộ lọc, thì tất nhiên phép biến đổi sẽ áp dụng trước bộ lọc.

Mỗi phần tử DOM có một trạng thái cây thuộc tính. Đó là 4 bộ (biến đổi, cắt, hiệu ứng, cuộn) cho biết đoạn cắt đối tượng cấp trên, biến đổi và nút cây hiệu ứng gần nhất có hiệu lực trên phần tử đó. Điều này rất thuận tiện, vì với thông tin này, chúng ta biết chính xác danh sách các đoạn video, phép biến đổi và hiệu ứng áp dụng cho phần tử đó cũng như thứ tự triển khai. Thông tin này cho chúng tôi biết vị trí của hình ảnh trên màn hình và cách vẽ hình ảnh đó.

Ví dụ:

(nguồn)

<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>

Đối với ví dụ trước (hơi khác so với ví dụ trong phần giới thiệu), dưới đây là các phần tử chính của cây thuộc tính được tạo:

Ví dụ về các phần tử trong cây thuộc tính.

Hiển thị danh sách và vẽ đoạn

Một mục hiển thị chứa các lệnh vẽ cấp thấp (xem tại đây) có thể tạo điểm ảnh bằng Skia. Các mục hiển thị thường rất đơn giản, chỉ với một vài lệnh vẽ, chẳng hạn như vẽ đường viền hoặc nền. Quá trình vẽ cây vẽ sẽ lặp lại cây bố cục và các mảnh liên kết theo đơn đặt hàng sơn CSS để tạo danh sách mục hiển thị.

Ví dụ:

Một hộp màu xanh dương có dòng chữ &quot;Hello world&quot; bên trong một hình chữ nhật màu xanh lục.

<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 và CSS này sẽ tạo danh sách hiển thị sau đây, trong đó mỗi ô là một mục hiển thị:

Nền của chế độ xem #blue nền #green nền #green văn bản cùng dòng
drawRect có kích thước 800x600, màu trắng. drawRect với kích thước 100x100 ở vị trí 0,0 và màu xanh dương. drawRect với kích thước 80x18 ở vị trí 8,8 và màu xanh lục. drawTextBlob với vị trí 8,8 và dòng chữ "Hello world".

Danh sách mặt hàng hiển thị được sắp xếp theo thứ tự từ sau ra trước. Trong ví dụ trên, div màu xanh lục đứng trước div màu xanh dương theo thứ tự DOM, nhưng thứ tự tô màu CSS yêu cầu div màu xanh dương có chỉ số z phủ định trước (bước 3) div màu xanh lục (bước 4.1). Các mục hiển thị tương ứng gần đúng với các bước nguyên tử của quy cách đơn đặt hàng sơn CSS. Một phần tử DOM có thể dẫn đến nhiều mục hiển thị, chẳng hạn như #green có một mục hiển thị cho nền và một mục hiển thị khác cho văn bản cùng dòng. Độ chi tiết này rất quan trọng để thể hiện toàn bộ độ phức tạp của quy cách đơn đặt hàng sơn CSS, chẳng hạn như việc xen kẽ được tạo bằng lề âm:

Một hình chữ nhật màu xanh lục, với một hộp màu xám được bao phủ một phần và dòng chữ &quot;Hello world&quot;.

<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>

Thao tác này sẽ tạo ra danh sách hiển thị sau đây, trong đó mỗi ô là một mục hiển thị:

Nền của chế độ xem #green nền #gray nền #green văn bản cùng dòng
drawRect có kích thước 800x600, màu trắng. drawRect với kích thước 80x18 ở vị trí 8,8 và màu xanh lục. drawRect với kích thước 35x20 ở vị trí 8,16 và màu xám. drawTextBlob với vị trí 8,8 và dòng chữ "Hello world".

Danh sách mặt hàng hiển thị được lưu trữ và sử dụng lại trong các bản cập nhật sau này. Nếu một đối tượng bố cục không thay đổi trong quá trình vẽ cây, thì các mục hiển thị của đối tượng đó sẽ được sao chép từ danh sách trước đó. Tính năng tối ưu hoá bổ sung dựa trên thuộc tính của thông số kỹ thuật thứ tự sơn CSS: xếp chồng các ngữ cảnh vẽ một cách tỉ mỉ. Nếu không có đối tượng bố cục nào thay đổi trong ngữ cảnh xếp chồng, thì quá trình cây vẽ sẽ bỏ qua ngữ cảnh xếp chồng và sao chép toàn bộ trình tự các mục hiển thị từ danh sách trước.

Trạng thái cây thuộc tính hiện tại được duy trì trong quá trình đi bộ cây sơn và danh sách mục hiển thị được nhóm thành "các phần" gồm các mục hiển thị có cùng trạng thái cây thuộc tính. Điều này được minh hoạ trong ví dụ sau:

Một chiếc hộp màu hồng với một chiếc hộp màu cam nghiêng.

<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>

Thao tác này sẽ tạo ra danh sách hiển thị sau đây, trong đó mỗi ô là một mục hiển thị:

Nền của chế độ xem #scroll nền #scroll văn bản cùng dòng #orange nền #orange văn bản cùng dòng
drawRect có kích thước 800x600, màu trắng. drawRect với kích thước 100x100 ở vị trí 0,0 và màu hồng. drawTextBlob với vị trí 0,0 và văn bản "Hello world". drawRect với kích thước 75x200 ở vị trí 0,0 và màu cam. drawTextBlob với vị trí 0,0 và văn bản "Tôi đang rơi".

Sau đó, cây thuộc tính biến đổi và các đoạn sơn sẽ được (đơn giản hoá cho ngắn gọn):

Hình ảnh của bảng trước, hai ô đầu tiên trong đoạn 1, ô thứ ba trong đoạn 2, hai ô cuối cùng trong đoạn 3.

Danh sách các đoạn sơn được sắp xếp theo thứ tự, là các nhóm mục hiển thị và trạng thái cây thuộc tính, là các dữ liệu đầu vào cho bước phân lớp của quy trình kết xuất. Có thể hợp nhất toàn bộ danh sách các khối sơn thành một lớp tổng hợp và tạo điểm ảnh cùng nhau, nhưng điều này sẽ đòi hỏi việc tạo điểm ảnh tốn kém mỗi khi người dùng cuộn. Bạn có thể tạo một lớp tổng hợp cho từng đoạn sơn và tạo điểm ảnh riêng lẻ để tránh tạo lại điểm ảnh lại, nhưng việc đó sẽ nhanh chóng làm cạn kiệt bộ nhớ GPU. Bước phân lớp phải đưa ra sự đánh đổi giữa bộ nhớ GPU và giảm chi phí khi mọi thứ thay đổi. Một phương pháp chung hay là hợp nhất các đoạn theo mặc định và không hợp nhất các đoạn sơn có trạng thái cây thuộc tính dự kiến sẽ thay đổi trên luồng của trình tổng hợp, chẳng hạn như với ảnh động biến đổi luồng của trình tổng hợp hoặc của trình tổng hợp.

Ví dụ trước nên tạo hai lớp kết hợp lý tưởng:

  • Một lớp kết hợp có kích thước 800x600 chứa các lệnh vẽ:
    1. drawRect có kích thước 800x600 và màu trắng
    2. drawRect có kích thước 100x100 ở vị trí 0,0 và màu hồng
  • Một lớp kết hợp có kích thước 144x224 chứa các lệnh vẽ:
    1. drawTextBlob với vị trí 0,0 và dòng chữ "Hello world" (Xin chào mọi người)
    2. dịch 0,18
    3. rotateZ(25deg)
    4. drawRect với kích thước 75x200 ở vị trí 0,0 và màu cam
    5. drawTextBlob với vị trí 0,0 và văn bản "Tôi đang rơi"

Nếu người dùng cuộn #scroll, lớp tổng hợp thứ hai sẽ được di chuyển nhưng không cần tạo điểm ảnh.

Ví dụ tại đây, trong phần trước về cây thuộc tính, có 6 đoạn sơn. Cùng với các trạng thái cây thuộc tính (biến đổi, cắt, hiệu ứng, cuộn), chúng bao gồm:

  • Nền tài liệu: cuộn tài liệu, đoạn tài liệu, gốc, cuộn tài liệu.
  • Góc ngang, dọc và cuộn cho div (ba đoạn sơn riêng biệt): cuộn tài liệu, đoạn tài liệu, làm mờ #one, cuộn tài liệu.
  • Iframe #one: Xoay #one, nút cuộn tràn, làm mờ #one, cuộn div.
  • Iframe #two: Tỷ lệ #two, đoạn tài liệu, gốc, cuộn tài liệu.

Khung tổng hợp: bề mặt, giao diện kết xuất và ô hoạ tiết GPU

Như đã thảo luận trong bài đăng trước (ví dụ đã hoạt động tại đây), trình duyệt và các quy trình kết xuất sẽ quản lý việc tạo điểm ảnh nội dung, sau đó gửi khung tổng hợp đến quy trình Viz để trình bày lên màn hình. Khung của bộ tổng hợp là cách RenderingNG thể hiện cách ghép các nội dung đã tạo điểm ảnh lại với nhau cũng như vẽ một cách hiệu quả bằng cách sử dụng GPU.

Thẻ thông tin

Trên lý thuyết, trình tổng hợp quy trình kết xuất hoặc trình duyệt có thể tạo điểm ảnh thành một hoạ tiết đơn lẻ với kích thước đầy đủ của khung nhìn kết xuất và gửi hoạ tiết đó lên Viz. Để hiển thị, trình tổng hợp hiển thị sẽ chỉ phải sao chép các pixel từ một hoạ tiết đó vào vị trí thích hợp trong vùng đệm khung (ví dụ: màn hình). Tuy nhiên, nếu trình tổng hợp đó muốn cập nhật ngay cả một pixel, thì trình tổng hợp đó cần phải tạo lại điểm ảnh toàn bộ khung nhìn và gửi hoạ tiết mới lên Viz.

Thay vào đó, khung nhìn được chia thành các ô. Một ô hoạ tiết GPU riêng biệt phía sau mỗi ô có các pixel đã tạo điểm ảnh cho một phần của khung nhìn. Sau đó, trình kết xuất có thể cập nhật từng thẻ thông tin hoặc thậm chí chỉ cần thay đổi vị trí trên màn hình cho các thẻ thông tin hiện có. Ví dụ: khi cuộn trên một trang web, vị trí của các thẻ thông tin hiện có sẽ dịch chuyển lên và chỉ thỉnh thoảng bạn cần tạo điểm ảnh cho nội dung ở phía dưới trang.

4 ô.

Hình ảnh trên mô tả một ngày đầy nắng với bốn ô. Khi thao tác cuộn diễn ra, ô thứ năm sẽ bắt đầu xuất hiện. Một trong các thẻ thông tin có vẻ chỉ có một màu (màu xanh da trời) và có một video và một iframe ở trên cùng. Điều này dẫn đến chủ đề tiếp theo.

Hình tứ giác và mặt phẳng

Thẻ thông tin GPU là một loại quad đặc biệt, chỉ là một cái tên thú vị cho một danh mục hoạ tiết hoặc danh mục khác. Hình tứ giác xác định hoạ tiết đầu vào, đồng thời cho biết cách chuyển đổi và áp dụng hiệu ứng hình ảnh cho hoạ tiết đó. Ví dụ: ô nội dung thông thường có phép biến đổi cho biết vị trí x, y của chúng trong lưới ô.

Ô hoạ tiết GPU.

Những ô được tạo điểm ảnh này được gói trong một thẻ kết xuất, là danh sách các tứ giác. Lượt kết xuất không chứa bất kỳ thông tin pixel nào; thay vào đó, lượt kết xuất có hướng dẫn về vị trí và cách vẽ từng góc để tạo đầu ra pixel mong muốn. Có một khung vẽ cho mỗi thẻ thông tin hoạ tiết GPU. Trình tổng hợp màn hình chỉ cần lặp lại qua danh sách các tứ giác, vẽ từng khung hình bằng các hiệu ứng hình ảnh đã chỉ định, để tạo ra đầu ra pixel mong muốn cho lượt kết xuất. Việc kết hợp các tứ giác vẽ cho một lượt kết xuất có thể được thực hiện hiệu quả trên GPU, vì các hiệu ứng hình ảnh được phép được chọn là các hiệu ứng ánh xạ trực tiếp tới các tính năng GPU.

Có nhiều loại hình tứ giác khác ngoài các ô được tạo điểm ảnh. Ví dụ: có các khung vẽ màu đồng nhất không có hoạ tiết nào được hỗ trợ hoặc các khung vẽ có hoạ tiết đối với hoạ tiết không phải hoạ tiết như video hoặc canvas.

Một khung trình tổng hợp cũng có thể nhúng một khung trình tổng hợp khác. Ví dụ: trình tổng hợp trình duyệt tạo ra một khung trình tổng hợp với giao diện người dùng của trình duyệt và một hình chữ nhật trống nơi nội dung trình tổng hợp kết xuất sẽ được nhúng. Một ví dụ khác là iframe tách biệt trang web. Việc nhúng này được thực hiện thông qua các nền tảng.

Khi trình tổng hợp gửi một khung tổng hợp, đi kèm với một giá trị nhận dạng, gọi là mã nhận dạng bề mặt, cho phép các khung tổng hợp khác nhúng khung đó bằng cách tham chiếu. Viz lưu trữ khung trình tổng hợp mới nhất được gửi cùng với một mã nền tảng cụ thể. Sau đó, một khung trình tổng hợp khác có thể tham chiếu đến khung này thông qua một bề mặt vẽ quad, và do đó Viz biết phải vẽ gì. (Lưu ý rằng các góc vẽ bề mặt chỉ chứa mã nhận dạng bề mặt chứ không chứa hoạ tiết.)

Thẻ kết xuất trung gian

Một số hiệu ứng hình ảnh, chẳng hạn như nhiều bộ lọc hoặc chế độ trộn nâng cao, yêu cầu phải vẽ ít nhất 2 tứ phân vào một hoạ tiết trung gian. Sau đó, hoạ tiết trung gian được vẽ vào một vùng đệm đích trên GPU (hoặc có thể là một hoạ tiết trung gian khác), áp dụng hiệu ứng hình ảnh cùng lúc. Để cho phép việc này, một khung trình tổng hợp phải chứa danh sách các lượt kết xuất. Luôn có một lượt kết xuất gốc, được vẽ cuối cùng và có đích đến tương ứng với vùng đệm khung, ngoài ra còn có thể có nhiều hơn nữa.

Khả năng có nhiều lượt kết xuất sẽ giải thích tên "lượt hiển thị". Mỗi lượt truyền phải được thực thi tuần tự trên GPU, trong nhiều "lượt truyền", trong khi đó một lượt truyền duy nhất có thể được hoàn tất trong một tính toán GPU song song hàng loạt.

Tổng hợp

Nhiều khung trình tổng hợp được gửi đến Viz và cần được vẽ cùng nhau lên màn hình. Điều này được thực hiện bằng một giai đoạn tổng hợp sẽ chuyển đổi các hình ảnh đó thành một khung trình tổng hợp tổng hợp duy nhất. Tính năng tổng hợp sẽ thay thế các tứ giác vẽ bề mặt bằng khung trình tổng hợp mà chúng chỉ định. Đây cũng là cơ hội để tối ưu hoá loại bỏ những hoạ tiết hoặc nội dung trung gian không cần thiết nhưng nằm ngoài màn hình. Ví dụ: trong nhiều trường hợp, khung tổng hợp cho iframe tách biệt của trang web không cần hoạ tiết trung gian riêng và có thể được vẽ trực tiếp vào vùng đệm khung thông qua các khung vẽ thích hợp. Giai đoạn tổng hợp sẽ tìm ra các biện pháp tối ưu hoá đó và áp dụng dựa trên kiến thức toàn cầu mà các trình tổng hợp kết xuất riêng lẻ không thể truy cập được.

Ví dụ:

Dưới đây là các khung trình tổng hợp thực tế minh hoạ ví dụ ở đầu bài đăng này.

  • Nền tảng foo.com/index.html: id=0
    • Kết xuất thẻ 0: vẽ thành đầu ra.
      • Kết xuất lượt vẽ quad: vẽ với làm mờ 3px và cắt thành luồng kết xuất 0.
        • Thẻ kết xuất 1:
          • Vẽ tứ giác cho nội dung thẻ thông tin của iframe #one, với vị trí x và y cho mỗi nội dung.
      • Bề mặt được vẽ quad: có ID 2, được vẽ bằng tỷ lệ và chuyển đổi dịch chuyển.
  • Nền tảng giao diện người dùng của trình duyệt: ID=1
    • Kết xuất thẻ 0: vẽ thành đầu ra.
      • Vẽ hình tứ giác cho giao diện người dùng của trình duyệt (cũng xếp kề)
  • Nền tảng bar.com/index.html: ID=2
    • Kết xuất thẻ 0: vẽ thành đầu ra.
      • Vẽ tứ giác cho nội dung của iframe #two, với vị trí x và y cho mỗi nội dung.

Kết luận

Cảm ơn bạn đã đọc! Cùng với hai bài đăng trước, bài đăng này kết thúc thông tin tổng quan về RenderingNG. Tiếp theo sẽ là tìm hiểu sâu về những thách thức và công nghệ trong nhiều thành phần phụ của quy trình kết xuất, từ đầu đến cuối. Tính năng này sẽ sớm ra mắt!

Hình minh hoạ của Una Kravets.