2016-01-28 15 views
6

Tốc độ bit của Win32 nhanh hơn rất nhiều so với SetPixelV hoặc một chức năng khác chẳng hạn như. Làm thế nào để làm việc này, nếu ở cuối máy tính sẽ được vẽ pixel cho bitmap?Làm cách nào để hiển thị bitmap của Win32 nhanh hơn pixel?

+2

'SetPixelV' áp đặt rất nhiều chi phí gọi hàm để vẽ một pixel. –

+1

[BitBlt] (https://msdn.microsoft.com/en-us/library/dd183370.aspx) thường được tăng tốc phần cứng, trong đó CPU chỉ cần phát hành một vài lệnh cho phần cứng, thực hiện chuyển khối ký ức. – IInspectable

+1

Việc cập nhật đồ họa nhanh thường xảy ra từ việc sao chép các khối pixel lớn cùng một lúc; thường xuyên bằng cách sử dụng phần cứng được thiết kế đặc biệt để làm điều đó. – mah

Trả lời

5

Giả sử bạn có pixel. Pixel này có các thành phần màu A B và C. Bề mặt bạn vẽ có các thành phần màu X Y và Z.

Vì vậy, trước tiên bạn cần phải kiểm tra xem chúng có khớp không. Nếu chúng không khớp, chi phí sẽ tăng lên. Giả sử chúng khớp nhau.

Tiếp theo, bạn cần kiểm tra giới hạn - người gọi có cho bạn điều gì đó ngu ngốc không? Một số so sánh, bổ sung và nhân.

Tiếp theo, bạn cần tìm vị trí của pixel. Đây là một số phép nhân và bổ sung.

Bây giờ, bạn phải truy cập dữ liệu nguồn và dữ liệu đích và ghi dữ liệu đó.


Nếu bạn đang làm việc quét tại một thời điểm, hầu như toàn bộ chi phí trên có thể được thực hiện một lần. Bạn có thể tính toán phần nào của đường quét rơi vào giới hạn hoặc không chỉ với chi phí cao hơn một chút so với thực hiện một pixel. Bạn có thể tìm thấy nơi scanline ghi trong đích với một lần nữa chỉ cao hơn một chút so với một pixel. Bạn có thể kiểm tra chuyển đổi không gian màu với cùng chi phí như một pixel.

Sự khác biệt lớn là thay vì sao chép một pixel, bạn sao chép vào một khối.

Khi điều đó xảy ra, máy tính thực sự tốt trong việc sao chép các khối của sự vật. Có một số hướng dẫn tích hợp trên một số CPU, một số hệ thống bộ nhớ có thể thực hiện nó mà không cần CPU liên quan (CPU nói "copy X to Y", sau đó có thể thực hiện các thao tác khác và băng thông bộ nhớ có thể cao hơn bộ nhớ- từ bộ nhớ đến CPU). Ngay cả khi bạn đang đi vòng qua CPU, có hướng dẫn SIMD cho phép bạn làm việc trên 2, 4, 8, 16 hoặc thậm chí nhiều đơn vị dữ liệu hơn cùng một lúc, miễn là bạn làm việc trên chúng theo cách tương tự bằng cách sử dụng một tập lệnh giới hạn.

Trong một số trường hợp, bạn thậm chí có thể tải công việc xuống GPU - nếu cả quét nguồn và đích đều nằm trên GPU, bạn có thể nói "GPU yo, bạn xử lý" và GPU thậm chí còn chuyên biệt hơn để thực hiện loại nhiệm vụ đó.

Bit đầu tiên tối ưu hóa - chỉ phải thực hiện kiểm tra một lần trên mỗi lần quét thay vì một lần cho mỗi pixel - có thể dễ dàng cung cấp cho bạn tốc độ 2x đến ~ 10x. Thứ hai - hiệu quả hơn blitting - một 4x đến ~ 20x nhanh hơn. Làm mọi thứ trên GPU có thể nhanh hơn gấp 2 đến 2 lần.

Điều cuối cùng là chi phí thực sự gọi hàm. Thông thường điều này là nhỏ; nhưng khi gọi SetPixel 1 triệu lần (một hình ảnh 1000 x 1000 hoặc một màn hình có kích thước khiêm tốn) nó sẽ tăng lên.

Đối với màn hình HD có 2 triệu pixel, 60 lần mỗi giây là 120 triệu pixel được xử lý mỗi giây. Một chương trình đơn luồng trên một máy 3 GHz chỉ có chỗ để chạy ~ 25 hướng dẫn trên mỗi pixel nếu bạn muốn theo kịp màn hình và giả định không có gì khác xảy ra (điều này không chắc). Trên màn hình 4k, bạn có 6 hướng dẫn trên mỗi pixel.

Với nhiều pixel được chơi cùng, hãy tắt mọi hướng dẫn bạn có thể tạo sự khác biệt lớn.


Nhân được rút ra khỏi hư không. Tôi đã viết một số chuyển đổi của các hoạt động trên mỗi pixel cho các hoạt động trên mỗi lần quét đã cho thấy các tăng tốc ấn tượng, tuy nhiên, và ditto cho tải CPU đến GPU, và đã thấy SIMD cho các tăng tốc ấn tượng.

2

Các cuộc gọi lặp lại với một chức năng như SetPixelV chậm vì nó phải dịch phối hợp thành bộ nhớ bù trừ mỗi lần và cũng có khả năng thực hiện một số bản dịch màu khi đang di chuyển.

Một đơn giản "thiết lập pixel" chức năng thể giống như thế này (không có giới hạn-kiểm tra, màu sắc dịch hoặc bất cứ điều gì ưa thích):

size_t offset = y * bytes_per_scanline + x * bytes_per_pixel; 
for(size_t i = offset; i < offset + bytes_per_pixel; i++) 
    target[i] = source[i]; 

Bitmaps, mặt khác, thường được rút ra qua một quá trình được gọi là ghi số. Đây thực chất là bản sao trực tiếp từ vị trí bộ nhớ này đến vị trí bộ nhớ khác. Để đạt được điều này trong Windows, bạn tạo ngữ cảnh thiết bị cho bitmap của mình là tương thích với ngữ cảnh đích. Điều đó đảm bảo bộ nhớ có thể được sao chép mà không cần dịch. Nó cũng có thể cung cấp cho các bản sao tăng tốc phần cứng thậm chí còn nhanh hơn.

Một đơn giản "sao chép" blit có thể trông như thế này:

size_t nbytes = bytes_per_scanline * height; 
for(size_t i = 0; i < nbytes; i++) 
    target[i] = source[i]; 

này liên quan đến không tra cứu phối hợp, và sẽ rất hiệu quả về bộ nhớ cache truy cập. Có nhiều cách nhanh hơn để sao chép các phần bộ nhớ, và ví dụ trên chỉ đơn giản là minh họa.

+0

xin lỗi nếu nó hơi trễ và nếu điều này không có chủ đề, nhưng ý của bạn là gì? "Có nhiều cách nhanh hơn để sao chép khối bộ nhớ, và ví dụ trên chỉ đơn giản là minh họa."? Bạn có thể cho tôi một trong số họ không? Tôi sẽ sớm chuyển sang các nền tảng khác và do đó có thể cần phải tự triển khai chúng. –

+0

Ví dụ về vòng lặp sao chép đó đang sao chép một byte đơn tại một thời điểm. Nếu trình biên dịch không thể xác định bất kỳ sự bảo đảm nào về kích thước tại thời gian biên dịch, hoặc quyết định các đường dẫn mã thay thế trong thời gian chạy, thì nó sẽ là một vòng lặp crappy. Tối ưu hóa tốt hơn là sao chép theo khối. Sau đó, có ít đếm vòng lặp và sao chép thực tế hơn. Các công nghệ vector như MMX, SSE và AVX cung cấp kích thước đăng ký lớn hơn (64 bit, 128 bit, 256 bit, 512 bit) và giúp sao chép nhanh hơn. Kết hợp với việc bỏ vòng lặp, bạn có thể có hiệu suất cao hơn. Tất cả điều này là xuống đến những thứ bạn thực sự biết (hoặc có thể đảm bảo) về dữ liệu của bạn. – paddy

Các vấn đề liên quan