Các cấu trúc dữ liệu chính 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

Hãy xem xét các cấu trúc dữ liệu chính, đó là dữ liệu đầu vào và đầu ra của quy trình kết xuất.

Các cấu trúc dữ liệu này là:

  • Cây khung bao gồm các nút cục bộ và từ xa, đại diện cho tài liệu web nào đang ở quy trình kết xuất nào và trình kết xuất Blink nào.
  • Cây mảnh không thể thay đổi thể hiện đầu ra của (và đầu vào cho) thuật toán ràng buộc bố cục.
  • Cây thuộc tính thể hiện hệ phân cấp biến đổi, cắt đoạn, hiệu ứng và cuộn của tài liệu web. Các thông số này được sử dụng trong toàn bộ quy trình.
  • Danh sách hiển thị và các đoạn sơn là dữ liệu đầu vào cho thuật toán quét và phân lớp.
  • Khung trình tổng hợp đóng gói các nền tảng, nền tảng kết xuất và thẻ 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, ví dụ sau đây sẽ dựa trên một ví dụ trong phần xem xét cấu trúc. Ví dụ này được sử dụng trong toàn bộ tài liệu kèm theo thông tin minh hoạ cách áp dụng các cấu trúc dữ liệu.

<!-- Example code -->
<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 kết xuất một khung đa nguồn gốc trong một quy trình kết xuất khác với khung mẹ.

Trong mã ví dụ, 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ử dụng hai quy trình kết xuất để hiển thị trang web này. Mỗi quá trình kết xuất có một đại diện riêng trong cây khung cho trang web đó:

Hai cây khung hình đại diện cho hai quy trình kết xuấ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 để đóng vai trò là phần giữ chỗ trong quá trình kết xuất, chẳng hạn như kích thước của khung. Nếu không, khung từ xa không chứa bất kỳ thông tin nào cần thiết để kết xuất nội dung thực tế.

Ngược lại, khung cục bộ đại diện cho một khung hình đi qua quy trình kết xuất tiêu chuẩn. 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ư cây DOM và dữ liệu kiểu) thành nội dung có thể kết xuất và hiển thị.

Quy trình kết xuất hoạt động theo mức độ chi tiết của 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àm khung chính:

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

Và khung con bar.com sau:

<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ó ba mảnh cây khung cục bộ, trong đó hai mảnh trong quá trình kết xuất cho foo.com và một mảnh trong quá trình kết xuất cho bar.com:

Hình ảnh đại diện cho hai kết xuất và ba mảnh cây khung.

Để tạo một khung tổng hợp cho trang web, Viz đồng thời yêu cầu một khung tổng hợp từ khung gốc của mỗi trong số ba cây khung cục bộ, sau đó tổng hợp các khung đó. Hãy tham khảo thêm phần khung trình tổng hợp.

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, hai khung này vẫn có vòng đời tài liệu độc lập vì chúng là một phần của các mảnh cây khung cục bộ khác nhau. Do đó, bạn không thể tạo một khung trình tổng hợp cho cả hai trong một lần cập nhật. Quá trình kết xuất không có đủ thông tin để kết hợp khung trình kết hợp được tạo cho foo.com/other-page trực tiếp vào khung trình kết 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 biến đổi iframe bằng CSS hoặc che các phần của iframe bằng các phần tử khác trong DOM.

Quy trình cập nhật thuộc tính hình ảnh theo kiểu thác nước

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ả kết xuất và phải được đồng bộ hoá giữa các mảnh cây khung cục bộ. Phần 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 nó. Nội dung 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 phổ biến đến 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ơ đồ về quy trình được giải thích trong văn bản trước.

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

Cây mảnh không thể thay đổi

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

Giá trị đại diện của các mảnh trong mỗi cây, với 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 phần tử DOM. Thông thường, mỗi phần tử chỉ có một mảnh, nhưng có thể có nhiều mảnh hơn nếu mảnh đó được chia trên nhiều trang khi in hoặc các cột khi ở ngữ cảnh nhiều cột.

Sau khi bố cục, mỗi mảnh sẽ trở thành không thể thay đổi và không bao giờ thay đổi nữa. Quan trọng là chúng tôi cũng áp dụng một số quy định hạn chế khác. Chúng tôi không:

  • Cho phép mọi tệp đối chiếu "lên" trong cây. (Thành phần con không thể có con trỏ đến thành phần mẹ.)
  • "Bong bóng" dữ liệu xuống cây (một phần tử con chỉ đọc thông tin từ các phần tử con của nó, chứ không phải từ phần tử 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 quy tắc hạn chế này, chúng ta thường phải tạo lại toàn bộ cây, điều này sẽ tốn kém.

Hầu hết bố cục thường là 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 khi 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 tương xứng 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 nhất có thể của cây trước đó. Điều này có nghĩa là (thường) chúng ta chỉ cần tạo lại trục chính của cây.

Trong tương lai, thiết kế không thể thay đổi này có thể cho phép chúng ta làm những việc thú vị như truyền cây mảnh không thể thay đổi qua các 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 bố cục mượt mà hoặc thực hiện bố cục dự đoán song song. Điều này cũng mang lại cho chúng ta tiềm năng của bố cục nhiều luồng.

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

Nội dung nội tuyến (chủ yếu là văn bản được định 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 ta biểu thị nội dung cùng dòng trong một danh sách phẳng đại diện cho cây. Lợi ích chính là việc trình bày danh sách phẳng cho nội tuyến nhanh chóng, hữu ích cho việc kiểm tra hoặc truy vấn cấu trúc dữ liệu nội tuyến và tiết kiệm 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à 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.

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 theo 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 (đối tượng, số lượng thành phần 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>

Thuộc tính width được đặt thành 0 để dòng bao bọc giữa "Xin chào" và "ở đó".

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, ngữ cảnh đó sẽ có dạng 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)
  • (Box <span>, 1)
  • (Text "Hi", 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 như getClientRectscontenteditable. 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 vào cấu trúc dữ liệu phẳng thông qua một con trỏ thuận tiện.

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

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

Cây thuộc tính

DOM là một cây gồm các phần tử (cộng với các nút văn bản) và CSS có thể áp dụng nhiều kiểu cho các phần tử.

Điều này xuất hiện theo 4 cách:

  • 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à tạo điểm ảnh cho phần tử (chứ không phải các thành phần con cháu của phần tử đó).
  • Hình ảnh: hiệu ứng đường quét/vẽ được áp dụng cho cây con DOM, chẳng hạn như phép biến đổi, bộ lọc và đoạn cắt (clipping).
  • Cuộn: cắt góc bo tròn và căn chỉnh theo trục cũng như cuộn của cây con được chứa.

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

Hiệu ứng hình ảnh và hiệu ứng cuộn trên web rất phức tạp. Vì vậy, điều quan trọng nhất mà cây thuộc tính thực hiện là chuyển đổi độ 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 độ phức tạp của DOM và CSS. Điều này cho phép chúng tôi triển khai các thuật toán để tổng hợp và cuộn một cách tự tin hơn nhiều. Cụ thể:

  • Bạn có thể tập trung các phép tính hình học và các phép tính khác có khả năng dễ xảy ra lỗi vào một nơi.
  • Mức độ phức tạp của việc tạo và cập nhật cây thuộc tính được tách riêng thành một giai đoạn trong 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 sẽ dễ dàng và nhanh chóng hơn so với trạng thái DOM đầy đủ, nhờ đó, 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 ta càng có nhiều lợi ích từ việc lưu hình học vào bộ nhớ đệm, vì các trường hợp này 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 biệt quá trình kết hợp khỏi quá trình vẽ và quá trình 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 thành phần ngoài màn hình và ô hoạ tiết GPU.
  • Huỷ hiệu quả và chính xác sơn và đường quét.
  • Đo lường sự thay đổi bố cụcnội dung lớn nhất hiển thị trong Chỉ số quan trọng chính của 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 và cuộn CSS. (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. 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 clip khác như clip-path. Cây cuộn thể hiện thông tin về thao tác cuộn, chẳng hạn như cách cuộn chuỗi với nhau; cần thiết để thực hiện thao tác cuộn trên luồng trình kết hợp. Mỗi nút trong cây thuộc tính đại diện cho một hiệu ứng cuộn hoặc hiệu ứng hình ảnh do một phần tử DOM áp dụng. Nếu có nhiều hiệu ứng, thì 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 thớt của DOM. Ví dụ: nếu có 3 phần tử DOM có đoạn video tràn, thì sẽ có 3 nút cây đoạn video và cấu trúc của cây đoạn video sẽ tuân theo mối quan hệ khối chứa giữa các đoạn video tràn. Ngoài ra còn có các đườ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à do đó là thứ tự áp dụng của các nút. Ví dụ: nếu một phép biến đổi trên một phần tử DOM nằm bên 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à một bộ dữ liệu gồm 4 phần tử (biến đổi, cắt, hiệu ứng, cuộn) cho biết phần tử cắt, biến đổi và hiệu ứng gốc 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ự của các phần tử đó. Thông tin này cho chúng tôi biết vị trí của khung hiển thị trên màn hình cũng như cách vẽ.

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 (có phần khác với ví dụ trong phần giới thiệu), sau đâ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 tài sản.

Hiển thị danh sách và vẽ các phầ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ể được quét bằng Skia. Các mục trên màn hình thường đơn giản, chỉ cần một vài lệnh vẽ, chẳng hạn như vẽ đường viền hoặc nền. Bước đi trên cây sơn sẽ lặp lại cây bố cục và các mảnh được liên kết theo đơn đặt hàng vẽ CSS để tạo danh sách mặt hàng hiển thị.

Ví dụ:

Một hộp màu xanh dương, với dòng chữ &quot;Hello world&quot; (Xin chào thế giới) bên trong 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 ra danh sách hiển thị sau đây, trong đó mỗi ô là một mục hiển thị:

Nền của thành phần hiển thị #blue (âm thanh trong nền) #green (âm thanh trong nền) #green văn bản cùng dòng
drawRect có kích thước 800x600 và màu trắng. drawRect có kích thước 100x100 ở vị trí 0,0 và màu xanh dương. drawRect có kích thước 80x18 ở vị trí 8,8 và màu xanh lục. drawTextBlob ở vị trí 8,8 và dòng chữ "Hello world".

Danh sách mục hiển thị được sắp xếp từ sau ra trước. Trong ví dụ trên, div màu xanh lục nằm trước div màu xanh dương theo thứ tự DOM, nhưng thứ tự vẽ CSS yêu cầu div màu xanh dương có chỉ mục z âm phải vẽ 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 thứ tự vẽ CSS. Một phần tử DOM có thể tạo ra một số mục hiển thị, chẳng hạn như cách #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 nội tuyến. Mức độ chi tiết này rất quan trọng để thể hiện toàn bộ độ phức tạp của thông số kỹ thuật thứ tự vẽ CSS, chẳng hạn như tính năng xen kẽ do lề âm tạo ra:

Một hình chữ nhật màu xanh lục có hộp màu xám 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 thành phần hiển thị #green (âm thanh trong nền) #gray (âm thanh trong nền) #green văn bản cùng dòng
drawRect có kích thước 800x600 và màu trắng. drawRect có kích thước 80x18 ở vị trí 8,8 và màu xanh lục. drawRect có kích thước 35x20 ở vị trí 8,16 và màu xám. drawTextBlob ở vị trí 8,8 và dòng chữ "Hello world".

Danh sách mục 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 đi bộ 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 đó. Một phương pháp tối ưu hoá bổ sung dựa trên một thuộc tính của quy cách thứ tự vẽ CSS: các ngữ cảnh xếp chồng vẽ một cách nguyên tử. Nếu không có đối tượng bố cục nào thay đổi trong ngữ cảnh xếp chồng, thì bước đi 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ộ trong cây vẽ và danh sách mục hiển thị được nhóm thành "các phần" của 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 hộp màu hồng có một 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 thành phần hiển thị #scroll (âm thanh trong nền) #scroll văn bản cùng dòng #orange (âm thanh trong nền) #orange văn bản cùng dòng
drawRect có kích thước 800x600 và màu trắng. drawRect có kích thước 100x100 ở vị trí 0.0 và có màu hồng. drawTextBlob có vị trí 0,0 và văn bản "Hello world". drawRect có kích thước 75x200 ở vị trí 0,0 và màu cam. drawTextBlob có vị trí 0,0 và văn bản "I'm falling" (Tôi đang rơi).

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

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

Danh sách các phần sơn 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à dữ liệu đầu vào cho bước phân lớp của quy trình kết xuất. Toàn bộ danh sách các đoạn sơn có thể được hợp nhất thành một lớp kết hợp và được quét cùng nhau, nhưng điều này sẽ đòi hỏi quá trình quét 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 phân đoạn sơn và tạo điểm ảnh riêng lẻ để tránh tất cả quá trình tạo lại điểm ảnh, nhưng điều đó sẽ nhanh chóng làm cạn kiệt bộ nhớ GPU. Bước phân lớp phải đá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 trình tổng hợp, chẳng hạn như với tính năng cuộn luồng trình tổng hợp hoặc ảnh động biến đổi luồng trình tổng hợp.

Lý tưởng nhất là ví dụ trước sẽ tạo ra hai lớp kết hợp:

  • Một lớp kết hợp 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 144x224 chứa các lệnh vẽ:
    1. drawTextBlob có vị trí 0,0 và văn bản "Hello world" ("Xin chào thế giới")
    2. dịch 0,18
    3. rotateZ(25deg)
    4. drawRect có kích thước 75x200 ở vị trí 0,0 và màu cam
    5. drawTextBlob có vị trí 0,0 và văn bản "I'm falling" ("Tôi đang rơi")

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

Ví dụ: từ phần trước trên cây thuộc tính, có 6 đoạn tô. 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), các trạng thái này là:

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

Khung trình kết hợp: các nền tảng, nền tảng kết xuất và thẻ thông tin hoạ tiết GPU

Trình duyệt và quy trình kết xuất quản lý việc tạo điểm ảnh của nội dung, sau đó gửi khung tổng hợp đến quy trình Viz để hiển thị trên màn hình. Khung trình tổng hợp thể hiện cách ghép nội dung đã quét cùng nhau và vẽ nội dung đó một cách hiệu quả bằng GPU.

Thẻ thông tin

Theo 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 kết cấu duy nhất bằng kích thước đầy đủ của khung nhìn trình kết xuất và gửi kết cấu đó đến Viz. Để hiển thị kết cấu đó, trình tổng hợp màn hình chỉ cần sao chép các pixel từ kết cấu đó 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 kết hợp đó muốn cập nhật ngay cả một pixel, thì trình kết hợp đó sẽ cần phải quét lại toàn bộ khung nhìn và gửi một hoạ tiết mới đến Viz.

Thay vào đó, khung nhìn được chia thành các ô. Thẻ thông tin hoạ tiết GPU riêng biệt hỗ trợ từng thẻ thông tin bằng các pixel được quét đường quét 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ỉ 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 một trang web, vị trí của các thẻ thông tin hiện có sẽ dịch chuyển lên trên và chỉ thỉnh thoảng một thẻ thông tin mới cần được quét đường quét cho nội dung ở phía dưới trang.

4 thẻ thông tin.
Hình ảnh này mô tả một ngày nắng, với 4 ô. Khi thao tác cuộn xảy ra, thẻ thông tin thứ năm sẽ bắt đầu xuất hiện. Một trong các thẻ thông tin chỉ có một màu (xanh dương nhạt), có một video và một iframe ở trên cùng.

Hình tứ giác và bề mặt

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

Thẻ thông tin kết cấu GPU.

Các ô được quét đường này được gói trong một lượt kết xuất, là một danh sách các hình 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 hiển thị này có hướng dẫn về vị trí và cách vẽ từng quad để tạo đầu ra pixel mong muốn. Có một bộ tứ vẽ cho mỗi ô kết cấu GPU. Trình tổng hợp hiển thị chỉ phải lặp lại danh sách các phần tư, vẽ từng phần tử bằng hiệu ứng hình ảnh đã chỉ định để tạo đầu ra pixel mong muốn cho lượt kết xuất. Bạn có thể kết hợp các hình vẽ tứ giác cho một lượt kết xuất một cách hiệu quả trên GPU, vì các hiệu ứng hình ảnh được phép được chọn cẩn thận để liên kết trực tiếp với các tính năng GPU.

Ngoài các ô được quét đường quét, còn có các loại hình vẽ tứ giác khác. Ví dụ: có khối vẽ màu đồng nhất không được hỗ trợ bởi hoạ tiết nào cả, hoặc khối vẽ hoạ tiết cho hoạ tiết không xếp kề như video hoặc canvas.

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

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

Lượt 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ế độ kết hợp nâng cao, yêu cầu phải có 2 hoặc nhiều quad được vẽ trên một hoạ tiết trung gian. Sau đó, hoạ tiết trung gian được vẽ vào vùng đệm đích trên GPU (hoặc có thể là một hoạ tiết trung gian khác), đồng thời áp dụng hiệu ứng hình ảnh. Để cho phép điều này, khung trình tổng hợp thực sự 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ẽ sau cùng và đích đến tương ứng với vùng đệm khung hình, và có thể có nhiều lượt kết xuất hơn.

Khả năng có nhiều lượt kết xuất giải thích tên "lượt kết xuất". 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 có thể được hoàn tất trong một phép tính GPU song song khổng lồ.

Tổng hợp

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

Ví dụ:

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

  • Nền tảng foo.com/index.html: id=0
    • Bước kết xuất 0: vẽ để xuất.
      • Vẽ tứ giác trong lượt kết xuất: vẽ với độ mờ 3px và cắt vào lượt kết xuất 0.
        • Lượt kết xuất 1:
          • Vẽ hình 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 thẻ thông tin.
      • Bốn mặt vẽ bề mặt: có mã nhận dạng 2, được vẽ bằng phép biến đổi tỷ lệ và dịch.
  • Nền tảng giao diện người dùng của trình duyệt: ID=1
    • Lượt kết xuất 0: vẽ để xuất.
      • 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ề)
  • bar.com/index.html surface: ID=2
    • Bước kết xuất 0: vẽ để xuất.
      • Vẽ hình tứ giác cho nội dung của iframe #two, với vị trí x và y cho mỗi hình.

Ảnh minh hoạ của Una Kravets.