Kết xuất độ trễ thấp với gợi ý chưa đồng bộ hoá

Joe Medley
Joe Medley

Sự khác biệt trong phương thức kết xuất bằng bút cảm ứng

Các ứng dụng vẽ dựa trên bút cảm ứng được tạo cho web từ lâu đã gặp phải vấn đề về độ trễ vì một trang web phải đồng bộ hoá các bản cập nhật đồ hoạ với DOM. Trong mọi ứng dụng vẽ, độ trễ hơn 50 mili giây có thể ảnh hưởng đến hoạt động phối hợp tay và mắt của người dùng, khiến việc sử dụng ứng dụng trở nên khó khăn.

Gợi ý desynchronized cho canvas.getContext() sẽ gọi một đường dẫn mã khác bỏ qua cơ chế cập nhật DOM thông thường. Thay vào đó, gợi ý sẽ yêu cầu hệ thống cơ bản bỏ qua việc tổng hợp nhiều nhất có thể và trong một số trường hợp, vùng đệm cơ bản của canvas được gửi trực tiếp đến bộ điều khiển hiển thị của màn hình. Điều này giúp loại bỏ độ trễ gây ra do sử dụng hàng đợi trình kết hợp kết xuất.

Bạn đánh giá như thế nào sản phẩm?

Kết xuất đồng thời Sintel

Nếu bạn muốn xem đoạn mã, hãy di chuyển về phía trước. Để xem tính năng này trong thực tế, bạn cần một thiết bị có màn hình cảm ứng và tốt nhất là bút cảm ứng. (Ngón tay cũng dùng được.) Nếu có, bạn hãy thử các mẫu 2d hoặc webgl. Để biết thêm thông tin, hãy xem bản minh hoạ của Miguel Casas, một trong những kỹ sư đã triển khai tính năng này. Mở bản minh hoạ, nhấn vào nút phát, sau đó di chuyển thanh trượt qua lại một cách ngẫu nhiên và nhanh chóng.

Ví dụ này sử dụng một đoạn video dài 1 phút 21 giây từ phim ngắn Sintel của Durian, dự án phim mở Blender. Trong ví dụ này, phim được phát trong phần tử <video> có nội dung được kết xuất đồng thời cho phần tử <canvas>. Nhiều thiết bị có thể thực hiện việc này mà không bị xé hình, mặc dù các thiết bị hỗ trợ tính năng kết xuất vùng đệm trước như ChromeOS chẳng hạn có thể bị hiện tượng xé hình. (Bộ phim này hay nhưng rất đau lòng. Tôi đã vô dụng trong một giờ sau khi nhìn thấy nó. Hãy xem bạn đã cảnh báo mình).

Sử dụng gợi ý

Có nhiều cách khác để sử dụng độ trễ thấp ngoài việc thêm desynchronized vào canvas.getContext(). Tôi sẽ lần lượt trình bày từng vấn đề.

Tạo canvas

Trên một API khác, tôi sẽ thảo luận về việc phát hiện tính năng trước. Đối với gợi ý desynchronized, trước tiên, bạn phải tạo canvas. Gọi canvas.getContext() và chuyển vào đó gợi ý desynchronized mới với giá trị true.

const canvas = document.querySelector('myCanvas');
const ctx = canvas.getContext('2d', {
  desynchronized: true,
  // Other options. See below.
});

Phát hiện tính năng

Tiếp theo, hãy gọi getContextAttributes(). Nếu đối tượng thuộc tính được trả về có thuộc tính desynchronized, hãy kiểm thử thuộc tính đó.

if (ctx.getContextAttributes().desynchronized) {
  console.log('Low latency canvas supported. Yay!');
} else {
  console.log('Low latency canvas not supported. Boo!');
}

Tránh nhấp nháy

Có hai trường hợp bạn có thể gây ra hiện tượng nhấp nháy nếu bạn viết mã không chính xác.

Một số trình duyệt, bao gồm cả Chrome, sẽ xoá canvas WebGL giữa các khung. Bộ điều khiển màn hình có thể đọc vùng đệm khi bộ đệm trống, khiến hình ảnh nhấp nháy. Để tránh tình trạng này, hãy đặt preserveDrawingBuffer thành true.

const canvas = document.querySelector('myCanvas');
const ctx = canvas.getContext('webgl', {
  desynchronized: true,
  preserveDrawingBuffer: true
});

Tình trạng nhấp nháy cũng có thể xảy ra khi bạn xoá ngữ cảnh trên màn hình trong mã vẽ của riêng mình. Nếu bạn phải xoá, hãy vẽ vào vùng đệm khung ngoài màn hình, sau đó sao chép đường đó vào màn hình.

Kênh alpha

Bạn vẫn có thể huỷ đồng bộ hoá một phần tử canvas trong suốt (một phần tử trong đó alpha được đặt thành true) nhưng không được có bất kỳ phần tử DOM nào khác phía trên.

Chỉ có thể có một

Bạn không thể thay đổi các thuộc tính ngữ cảnh sau lệnh gọi đầu tiên đến canvas.getContext(). Điều này luôn đúng nhưng việc lặp lại có thể giúp bạn tránh được sự thất vọng nếu bạn không biết hoặc đã quên .

Ví dụ: giả sử tôi nhận được một ngữ cảnh và chỉ định alpha là false, thì sau đó trong mã, tôi gọi canvas.getContext() lần thứ hai với alpha được đặt thành true như minh hoạ dưới đây.

const canvas = document.querySelector('myCanvas');
const ctx1 = canvas.getContext('2d', {
  alpha: false,
  desynchronized: true,
});

//Some time later, in another corner of code.
const ctx2 = canvas.getContext('2d', {
  alpha: true,
  desynchronized: true,
});

Rõ ràng là ctx1ctx2 là cùng một đối tượng. Alpha vẫn là giá trị false và ngữ cảnh có alpha bằng với giá trị true sẽ không bao giờ được tạo.

Các loại canvas được hỗ trợ

Tham số đầu tiên được truyền đến getContext()contextType. Nếu đã quen thuộc với getContext(), bạn sẽ chắc chắn liệu có còn loại bối cảnh "2d" nào được hỗ trợ hay không. Bảng dưới đây cho thấy các loại ngữ cảnh hỗ trợ desynchronized.

contextType Đối tượng loại ngữ cảnh

'2d'

CanvasRenderingContext2D

'webgl'

WebGLRenderingContext

'webgl2'

WebGL2RenderingContext

Kết luận

Nếu bạn muốn tìm hiểu thêm về nội dung này, hãy tham khảo các mẫu. Ngoài ví dụ về video đã mô tả, có các ví dụ cho thấy cả bối cảnh '2d''webgl'.