Mô hình lớp
Giới thiệu
Đối với hầu hết các nhà phát triển web, mô hình cơ bản của một trang web là DOM. Kết xuất là quá trình thường không rõ ràng để chuyển bản trình bày này của một trang thành hình ảnh trên màn hình. Các trình duyệt hiện đại đã thay đổi cách kết xuất hoạt động trong những năm gần đây để tận dụng thẻ đồ hoạ: điều này thường được gọi mơ hồ là "tăng tốc phần cứng". Khi nói về một trang web thông thường (ví dụ: không phải Canvas2D hoặc WebGL), thuật ngữ đó thực sự có nghĩa là gì? Bài viết này giải thích mô hình cơ bản làm cơ sở cho quá trình kết xuất tăng tốc phần cứng cho nội dung web trong Chrome.
Cảnh báo lớn, gây béo
Chúng tôi đang nói về WebKit ở đây và cụ thể hơn là chúng tôi nói về cổng Chromium của WebKit. Bài viết này trình bày thông tin triển khai của Chrome, chứ không đề cập đến các tính năng của nền tảng web. Nền tảng web và tiêu chuẩn không mã hoá cấp độ chi tiết triển khai này, vì vậy không có gì đảm bảo trong bài viết này sẽ áp dụng cho các trình duyệt khác, tuy nhiên kiến thức về nội bộ có thể hữu ích cho việc gỡ lỗi nâng cao và điều chỉnh hiệu suất.
Ngoài ra, xin lưu ý rằng toàn bộ bài viết này đang thảo luận về một phần cốt lõi trong kiến trúc kết xuất của Chrome đang thay đổi rất nhanh. Bài viết này cố gắng chỉ đề cập đến những nội dung không có khả năng thay đổi, nhưng không đảm bảo rằng tất cả sẽ vẫn được áp dụng sau sáu tháng.
Bạn cần hiểu rằng Chrome hiện đã có hai đường dẫn kết xuất khác nhau: đường dẫn được tăng tốc phần cứng và đường dẫn phần mềm cũ hơn. Tại thời điểm viết bài này, tất cả các trang đều đi theo đường dẫn được tăng tốc phần cứng trên Windows, ChromeOS và Chrome dành cho Android. Trên Mac và Linux, chỉ những trang cần tổng hợp cho một số nội dung của chúng mới đi theo đường dẫn được tăng tốc (xem bên dưới để biết thêm về những gì sẽ yêu cầu tổng hợp), nhưng tất cả các trang cũng sẽ sớm chuyển xuống đường dẫn được tăng tốc ở đó.
Cuối cùng, chúng ta sẽ tìm hiểu kỹ hơn về công cụ kết xuất hình ảnh và xem các tính năng có tác động lớn đến hiệu suất. Khi cố gắng cải thiện hiệu suất của trang web của bạn, việc hiểu mô hình lớp có thể rất hữu ích khi hiểu về mô hình lớp, nhưng cũng dễ dàng tự ghi nhận chính mình: lớp là cấu trúc hữu ích, nhưng việc tạo nhiều lớp có thể gây ra chi phí cao trên toàn bộ ngăn xếp đồ hoạ. Hãy coi là bạn đã tự cảnh báo trước!
Từ DOM đến Màn hình
Giới thiệu về Lớp
Khi một trang được tải và phân tích cú pháp, trang đó sẽ được thể hiện trong trình duyệt dưới dạng một cấu trúc mà nhiều nhà phát triển web quen thuộc: DOM. Tuy nhiên, khi hiển thị một trang, trình duyệt có một loạt các biểu diễn trung gian mà nhà phát triển không trực tiếp nhìn thấy. Thành phần quan trọng nhất trong các cấu trúc này là một lớp.
Trong Chrome thực tế có một số loại lớp khác nhau: RenderLayer chịu trách nhiệm tạo các cây con của DOM và Graphicslayer chịu trách nhiệm về các cây con của RenderLayer. Loại thứ hai là thú vị nhất đối với chúng tôi ở đây, vì GraphicsLayer là lớp được tải lên GPU dưới dạng hoạ tiết. Từ giờ trở đi tôi sẽ nói "layer" (lớp) có nghĩa là GraphicsLayer.
Ngoài thuật ngữ về GPU: kết cấu là gì? Bạn có thể xem đây là một hình ảnh bitmap được di chuyển từ bộ nhớ chính (ví dụ: RAM) sang bộ nhớ video (ví dụ: VRAM trên GPU). Sau khi nó ở trên GPU, bạn có thể ánh xạ nó đến một hình dạng lưới – trong trò chơi điện tử hoặc các chương trình CAD, kỹ thuật này được sử dụng để tạo ra “giao diện” cho các mô hình 3D bộ xương. Chrome sử dụng hoạ tiết để đưa các đoạn nội dung trang web lên GPU. Bạn có thể ánh xạ hoạ tiết tới các vị trí và phép biến đổi một cách tiết kiệm bằng cách áp dụng chúng vào một lưới hình chữ nhật thực sự đơn giản. Đây là cách CSS 3D hoạt động và cũng tuyệt vời để cuộn nhanh - nhưng sẽ thêm vào cả hai điều này sau.
Hãy xem một vài ví dụ để minh hoạ khái niệm về lớp.
Một công cụ rất hữu ích khi nghiên cứu các lớp trong Chrome là cờ “hiển thị đường viền lớp tổng hợp” trong cài đặt (tức là biểu tượng bánh răng nhỏ) trong Công cụ dành cho nhà phát triển, bên dưới tiêu đề “kết xuất”. Nó chỉ đơn giản là đánh dấu vị trí các lớp trên màn hình. Hãy bật tính năng này lên nào. Các ảnh chụp màn hình và ví dụ này đều được lấy từ phiên bản Chrome Canary mới nhất, Chrome 27 tại thời điểm chúng tôi viết bài này.
Hình 1: Trang một lớp
<!doctype html>
<html>
<body>
<div>I am a strange root.</div>
</body>
</html>
Trang này chỉ có một lớp. Lưới màu xanh dương biểu thị thẻ thông tin mà bạn có thể coi là các đơn vị con của lớp mà Chrome sử dụng để tải các phần của một lớp lớn lên GPU cùng một lúc. Chúng không thực sự quan trọng ở đây.
Hình 2: Một phần tử trong lớp của chính nó
<!doctype html>
<html>
<body>
<div style="transform: rotateY(30deg) rotateX(-30deg); width: 200px;">
I am a strange root.
</div>
</body>
</html>
Bằng cách đặt thuộc tính CSS 3D trên <div>
để xoay, chúng ta có thể thấy giao diện của một phần tử khi có lớp riêng: lưu ý đường viền màu cam sẽ phác thảo lớp trong chế độ xem này.
Tiêu chí tạo lớp
Mục nào khác sẽ có lớp riêng? Các phương pháp phỏng đoán của Chrome ở đây đã phát triển theo thời gian và vẫn tiếp tục phát triển, nhưng hiện tại là bất kỳ hoạt động tạo lớp trình kích hoạt nào sau đây:
- Thuộc tính CSS biến đổi 3D hoặc phối cảnh
<video>
phần tử sử dụng phương thức giải mã video được tăng tốc- Các phần tử
<canvas>
có bối cảnh 3D (WebGL) hoặc bối cảnh 2D được tăng tốc - Plugin tổng hợp (ví dụ: Flash)
- Các phần tử có ảnh động CSS để làm mờ hoặc sử dụng ảnh động biến đổi
- Các phần tử có bộ lọc CSS tăng tốc
- Phần tử có một phần tử con có một lớp kết hợp (nói cách khác nếu phần tử có một phần tử con nằm trong lớp riêng)
- Phần tử có một phần tử đồng cấp với chỉ mục z thấp hơn có một lớp kết hợp (nói cách khác, phần tử đó được hiển thị ở trên một lớp tổng hợp)
Áp dụng thực tế: Ảnh động
Chúng ta cũng có thể di chuyển các lớp xung quanh, do đó, việc sử dụng ảnh động sẽ rất hữu ích.
Hình 3: Lớp ảnh động
<!doctype html>
<html>
<head>
<style>
div {
animation-duration: 5s;
animation-name: slide;
animation-iteration-count: infinite;
animation-direction: alternate;
width: 200px;
height: 200px;
margin: 100px;
background-color: gray;
}
@keyframes slide {
from {
transform: rotate(0deg);
}
to {
transform: rotate(120deg);
}
}
</style>
</head>
<body>
<div>I am a strange root.</div>
</body>
</html>
Như đã đề cập trước đó, các lớp thực sự hữu ích để di chuyển xung quanh nội dung web tĩnh. Trong trường hợp cơ bản, Chrome vẽ nội dung của lớp thành bitmap phần mềm trước khi tải lên GPU dưới dạng kết cấu. Nếu sau này nội dung đó không thay đổi thì bạn không cần vẽ lại. Đây là một ưu điểm tốt: việc vẽ lại cần thời gian có thể dành cho các nội dung khác, như chạy JavaScript và nếu sơn quá dài, nó sẽ gây ra lỗi hoặc sự chậm trễ trong hoạt ảnh.
Ví dụ: xem chế độ xem này của dòng thời gian Công cụ dành cho nhà phát triển: không có hoạt động vẽ nào trong khi lớp này đang xoay qua lại.
Không hợp lệ! Sơn lại
Nhưng nếu nội dung của lớp thay đổi, nó phải được vẽ lại.
Hình 4: Lớp vẽ lại
<!doctype html>
<html>
<head>
<style>
div {
animation-duration: 5s;
animation-name: slide;
animation-iteration-count: infinite;
animation-direction: alternate;
width: 200px;
height: 200px;
margin: 100px;
background-color: gray;
}
@keyframes slide {
from {
transform: rotate(0deg);
}
to {
transform: rotate(120deg);
}
}
</style>
</head>
<body>
<div id="foo">I am a strange root.</div>
<input id="paint" type="button" value="repaint">
<script>
var w = 200;
document.getElementById('paint').onclick = function() {
document.getElementById('foo').style.width = (w++) + 'px';
}
</script>
</body>
</html>
Mỗi lần người dùng nhấp vào phần tử đầu vào, phần tử xoay sẽ rộng hơn 1px. Điều này dẫn đến việc bố cục lại và tô màu lại toàn bộ phần tử, trong trường hợp này là toàn bộ lớp.
Một cách hay để xem những gì đang được vẽ là sử dụng công cụ "hiển thị hình chữ nhật vẽ" trong Công cụ dành cho nhà phát triển, cũng bên dưới tiêu đề "Kết xuất" của cài đặt của Công cụ dành cho nhà phát triển. Sau khi bật, hãy chú ý đến cả thành phần ảnh động và nút đều nhấp nháy màu đỏ khi người dùng nhấp vào nút.
Các sự kiện tô màu cũng sẽ xuất hiện trong dòng thời gian của Công cụ dành cho nhà phát triển. Người đọc nhạy bén có thể nhận thấy có hai sự kiện vẽ ở đó: một cho lớp và một cho chính nút, được vẽ lại khi nút này chuyển sang/từ trạng thái bị nhấn.
Lưu ý rằng Chrome không phải lúc nào cũng cần vẽ lại toàn bộ lớp, trình duyệt sẽ cố gắng chỉ tô lại phần DOM đã bị vô hiệu hoá. Trong trường hợp này, phần tử DOM mà chúng ta đã sửa đổi là kích thước của toàn bộ lớp. Nhưng trong nhiều trường hợp khác, sẽ có nhiều phần tử DOM trong một lớp.
Một câu hỏi rõ ràng tiếp theo là điều gì gây ra hiệu lực không hợp lệ và buộc phải vẽ lại. Thật khó để trả lời đầy đủ về điều này vì có nhiều trường hợp hiếm gặp có thể buộc phải hợp lệ. Nguyên nhân phổ biến nhất là làm hỏng DOM bằng cách sửa đổi các kiểu CSS hoặc gây ra bố cục lại. Tony Gentilcore có một bài đăng trên blog rất hay về nguyên nhân dẫn đến bố cục lại và Stoyan Stefanov có một bài viết trình bày về việc vẽ tranh chi tiết hơn (nhưng kết thúc chỉ bằng bức tranh, chứ không phải nội dung kết hợp lạ mắt này).
Cách tốt nhất để tìm hiểu xem liệu việc này có ảnh hưởng đến công việc mà bạn đang xử lý hay không là sử dụng các công cụ Dòng thời gian của Công cụ dành cho nhà phát triển và Hiện hình chỉnh màu để xem liệu bạn có đang vẽ lại hay không, sau đó cố gắng xác định vị trí bạn đã làm bẩn DOM ngay trước khi bố cục lại/sơn lại đó. Nếu việc tô màu là không thể tránh khỏi nhưng có vẻ mất nhiều thời gian một cách không hợp lý, hãy xem bài viết của Eberhard Gräther về chế độ vẽ liên tục trong Công cụ dành cho nhà phát triển.
Tập trung: DOM lên màn hình
Vậy Chrome sẽ chuyển DOM thành hình ảnh màn hình bằng cách nào? Về mặt lý thuyết, ứng dụng:
- Lấy DOM và chia thành các lớp
- Vẽ từng lớp này một cách độc lập thành bitmap phần mềm
- Tải chúng lên GPU dưới dạng kết cấu
- Kết hợp nhiều lớp lại với nhau thành hình ảnh màn hình cuối cùng.
Tất cả những việc đó cần xảy ra ngay từ lần đầu tiên Chrome tạo khung của trang web. Tuy nhiên, bạn có thể thực hiện một số phím tắt cho các khung hình trong tương lai:
- Nếu một số thuộc tính CSS nhất định thay đổi, bạn không cần phải vẽ lại bất cứ thứ gì. Chrome chỉ có thể kết hợp lại các lớp hiện có đã tồn tại trên GPU dưới dạng kết cấu, nhưng với các thuộc tính kết hợp khác nhau (ví dụ: ở các vị trí khác nhau, với độ mờ khác nhau, v.v.).
- Nếu một phần của lớp không hợp lệ, lớp đó sẽ được vẽ lại và tải lên lại. Nếu nội dung của khung hình vẫn giữ nguyên nhưng các thuộc tính tổng hợp thay đổi (ví dụ: nội dung được dịch hoặc độ mờ thay đổi), thì Chrome có thể để lại nội dung trên GPU và kết hợp lại để tạo một khung hình mới.
Như bây giờ rõ ràng, mô hình kết hợp dựa trên lớp có ý nghĩa sâu sắc đối với hiệu suất kết xuất. Việc tổng hợp tương đối rẻ khi bạn không cần vẽ lại gì, vì vậy việc tránh sơn lại các lớp là một mục tiêu tổng thể tốt khi cố gắng gỡ lỗi kết xuất hiệu suất. Các nhà phát triển am hiểu sẽ xem xét danh sách các trình kích hoạt kết hợp ở trên và nhận ra rằng có thể dễ dàng buộc tạo lớp. Tuy nhiên, hãy cẩn thận khi tạo chúng một cách mù quáng vì chúng không miễn phí: chúng chiếm bộ nhớ trong RAM hệ thống và trên GPU (đặc biệt bị hạn chế trên thiết bị di động). Việc có quá nhiều chúng có thể gây ra hao tổn khác trong logic theo dõi chúng. Nhiều lớp thực sự cũng có thể làm tăng thời gian dành cho quá trình tạo điểm ảnh nếu các lớp đó lớn và chồng chéo nhiều ở nơi trước đây chúng không được tạo thành đường quét, dẫn đến điều này đôi khi được gọi là "vẽ nhiều lần". Vì vậy, hãy sử dụng kiến thức một cách khôn ngoan!
Video này đến đây là kết thúc. Hãy chú ý theo dõi một số bài viết khác về ý nghĩa thực tế của mô hình lớp.