Hiệu suất rất lớn khi sử dụng drawImage với IMG vs CANVAS


8

Tôi kết hợp một vài thử nghiệm đơn giản để đưa hình ảnh vào khung vẽ. Một kết xuất từ ​​một IMG, trong khi cái còn lại hiển thị từ CANVAS ngoài màn hình. Bạn có thể xem mã và kết quả tại đây: http://jsperf.com/canvas-rendering/2

Trong hầu hết các trình duyệt kết xuất từ ​​một hình ảnh nhanh hơn nhiều so với kết xuất từ ​​một khung vẽ, ngoại trừ trong Chrome, nơi tình huống được đảo ngược. Bất cứ ai có thể giải thích lý do cho sự khác biệt? Rốt cuộc, chúng ta đang hiển thị cùng một dữ liệu pixel cho cùng một đích.


2
Tôi không thực sự chắc chắn đây là một câu hỏi, hoặc ít nhất là một câu hỏi mà chúng tôi có thể trả lời. Mặc dù vậy, nhìn vào thử nghiệm của bạn, có vẻ như chỉ những người khác thực sự chậm trong việc hiển thị các đối tượng canvas, thay vì Chrome không bình thường để hiển thị hình ảnh chậm hơn.
Matt Kemp

Nhưng tại sao có sự khác biệt nào cả trong cả hai trường hợp chúng đều hiển thị cùng một dữ liệu? Và thực tế là ít nhất một trình duyệt chính có đặc tính hiệu năng ngược lại có nghĩa là chúng ta cần triển khai hai đường dẫn mã trong trình kết xuất.
alekop

Bạn có thể thêm vào kết xuất thử nghiệm mà không cần thẻ buffercanvas và img không? Sẽ rất thú vị để xem.
justanotherhulkist

@hustlerinc: Bạn có nghĩa là kết xuất từ ​​một khung vẽ lên chính nó? Điều đó sẽ chứng minh điều gì? Tất cả đồ họa của trò chơi được tải từ hình ảnh, vì vậy bạn phải sử dụng hình ảnh tại một số điểm trong quy trình.
alekop

@alekop Không, ý tôi là bỏ qua khung vẽ ngoài màn hình và chỉ sử dụng một khung vẽ. Tôi nghĩ trong web nó sẽ làm cho kết xuất nhanh hơn, nhưng không có bằng chứng cho nó. Và quá lười biếng / thiếu kinh nghiệm để tự làm bài kiểm tra.
justanotherhulkist

Câu trả lời:


9

OK, tôi đã tìm ra nó. Hầu hết. Nó thực sự khá rõ ràng và tôi cảm thấy hơi ngu ngốc khi không nhận ra điều này ngay lập tức. Khi bạn gọi drawImage(src, 0, 0)mà không chỉ định chiều rộng / chiều cao, nó sẽ vẽ toàn bộ vùng src, trong trường hợp này lớn hơn nhiều (khung vẽ là 320x420 so với img ở 185x70). Vì vậy, trong trường hợp canvas, trình duyệt đang làm việc nhiều hơn, điều này giải thích hiệu suất chậm hơn. Tôi vẫn còn bối rối với điểm số cao hơn của Chrome với src lớn hơn.

dest.drawImage(src, x, y) // bad
dest.drawImage(src, x, y, w, h, destX, destY, w, h) // good

Tôi đã đăng một phiên bản cập nhật sử dụng cùng các khu vực và sự khác biệt gần hơn nhiều. http://jsperf.com/canvas-rendering/5

Tôi vẫn không thể giải thích tại sao có sự khác biệt, nhưng giờ nó đủ nhỏ để tôi không thực sự quan tâm.


Trên Chrome 43 với Windows 8 và Intel Graphics HD, nó gặp sự cố khi thử nghiệm đầu tiên chạy. Khi thử nghiệm kết thúc drawImage (img) là người chiến thắng rõ ràng, drawImage (canvas) chậm hơn 94%.
Șerban

Firefox 38 chạy trơn tru, không có vấn đề gì cả, và cả hai bài kiểm tra đều gần nhau.
erban

Nếu bạn chia tỷ lệ hình ảnh của mình, điều đó cũng ảnh hưởng đến hiệu suất @alekop ( developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/ .)
Jersh

4

Chrome có khả năng sử dụng khả năng tăng tốc phần cứng.

Tạo một khung vẽ 240x240 và chạy thử nghiệm của bạn trong Chrome, sau đó tạo một khung vẽ 300x300 và thực hiện lại. Canvas lớn hơn tôi mong đợi sẽ nhanh hơn do thực tế tăng tốc phần cứng sau 256x256 và chrome sử dụng phần mềm khi kích thước nhỏ hơn.

Ngoài ra, nó đáng để chỉ ra rằng -webkit-Transform: translateZ (0) tắt tăng tốc phần cứng.

Tôi chưa thử nghiệm bất kỳ điều nào ở trên; Tôi chỉ biết điều này do thực tế là một trong những kỹ sư chrome đã nhận xét về lỗi tôi đã báo cáo bằng chrome khi bạn vượt qua ngưỡng phần cứng và phần mềm bằng cách tự động thay đổi kích thước khung vẽ từ lớn hơn nhỏ hơn ranh giới 256x256 hoặc ngược lại. Giải pháp cho lỗi này là tắt tăng tốc bằng cách sử dụng translZ như đã đề cập ở trên.

Trong trường hợp của tôi, tôi chỉ đơn giản là không cho phép người dùng thay đổi kích thước dưới 256x256.


Lần lượt tắt tăng tốc phần cứng? Nó không bật nó lên à?
gilbert-v

1

Đôi khi, hình ảnh có thể được tải vào bộ nhớ GPU và canvas trong bộ nhớ máy chủ. Trong trường hợp đó khi bạn vẽ từ hình ảnh sang khung vẽ, dữ liệu hình ảnh phải được sao chép trước tiên để lưu trữ bộ nhớ và sau đó vào khung vẽ.

Tôi nhận thấy loại hành vi đó với Chrome, khi tôi đang viết dự án tải hơn 100 triệu pixel hình ảnh và sau đó đọc các phần của chúng vào khung vẽ 256x256 nhỏ ( http://elhigu.github.io/canvas-image-tiles/ ).

Trong dự án đó, nếu tôi đã vẽ trực tiếp từ thẻ hình ảnh sang canvas trong Chrome, bộ nhớ luôn tăng lên ~ 1,5 GB khi bắt đầu vẽ và sau đó khi kết thúc vẽ, bộ nhớ đã được giải phóng, ngay cả hình ảnh nguồn 250 megapixel cũng được hiển thị mọi lúc trong trang.

Tôi đã khắc phục sự cố bằng cách viết hình ảnh một lần vào khung vẽ lớn (cùng kích thước với hình ảnh) và sau đó vẽ khung vẽ nhỏ hơn từ đó (Tôi cũng đã ném hình ảnh đi sau khi chuyển đổi nó thành khung vẽ).


0

Không thể giải thích sự khác biệt, nhưng tôi không đồng ý với

Và thực tế là ít nhất một trình duyệt chính có đặc tính hiệu năng ngược lại có nghĩa là chúng ta cần triển khai hai đường dẫn mã trong trình kết xuất. - alekop

Nếu bạn nhìn vào kết quả trên js.pref, sự khác biệt trong chrome khá tinh tế. Tôi chỉ muốn kết xuất từ ​​một hình ảnh khi có thể.


Vấn đề là tôi đang dựa vào các khung vẽ ngoài màn hình để sáng tác các hình ảnh phức tạp. Ví dụ: tôi kết xuất các khung hình hoạt hình của nhân vật vào bộ đệm ngoài màn hình và sau đó hiển thị những thứ như quần áo / áo giáp / vũ khí trên đầu. Trò chơi sau đó kết xuất từ ​​khung vẽ tổng hợp, thay vào đó hiển thị lại tất cả các chi tiết này cho từng nhân vật, từng khung hình. Với hiệu suất canvas-to-canvas rất kém trong các trình duyệt không phải Chrome, tôi phải kết xuất lại thành hình ảnh. Đó không phải là ngày tận thế, nhưng tôi đã hy vọng có một cách giải quyết.
alekop

0

Kích thước của hình ảnh là 185 * 70 nhưng chúng tôi tạo ra một khung vẽ có kích thước, tôi nghĩ rằng điều này sẽ lãng phí một số hiệu suất, vì vậy tôi đặt kích thước của khung vẽ ngoài màn hình giống như hình ảnh. Và sự khác biệt là gần hơn.

var g_offscreenCanvas = createCanvas(185, 70);

http://jsperf.com/canvas-rendering/60

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.