Khi nào một shader tính toán hiệu quả hơn một shader pixel để lọc ảnh?


37

Các hoạt động lọc hình ảnh như làm mờ, SSAO, nở hoa và v.v ... thường được thực hiện bằng cách sử dụng trình đổ bóng pixel và các hoạt động "tập hợp", trong đó mỗi lần gọi trình đổ bóng pixel tạo ra một số kết cấu tìm nạp để truy cập các giá trị pixel lân cận và tính toán một pixel kết quả. Cách tiếp cận này có một sự kém hiệu quả về mặt lý thuyết trong đó nhiều lần tìm nạp dự phòng đã được thực hiện: các yêu cầu đổ bóng gần đó sẽ lấy lại nhiều trong số các texels giống nhau.

Một cách khác để làm điều đó là với các shader tính toán. Chúng có lợi thế tiềm năng là có thể chia sẻ một lượng nhỏ bộ nhớ trong một nhóm các yêu cầu đổ bóng. Chẳng hạn, bạn có thể có mỗi lệnh gọi lấy một texel và lưu nó vào bộ nhớ dùng chung, sau đó tính kết quả từ đó. Điều này có thể hoặc có thể không nhanh hơn.

Câu hỏi đặt ra là trong trường hợp nào (nếu có) thì phương thức tính toán shader thực sự nhanh hơn phương thức pixel-shader? Có phụ thuộc vào kích thước của kernel, loại hoạt động lọc của nó, v.v.? Rõ ràng câu trả lời sẽ thay đổi từ một mô hình GPU sang một mô hình khác, nhưng tôi muốn nghe nếu có bất kỳ xu hướng chung nào.


Tôi nghĩ rằng câu trả lời là "luôn luôn" nếu trình đổ bóng tính toán được thực hiện đúng. Đây không phải là tầm thường để đạt được. Một shader tính toán cũng là một kết hợp tốt hơn so với một shader pixel về mặt khái niệm cho các thuật toán xử lý hình ảnh. Tuy nhiên, một pixel shader cung cấp ít thời gian hơn để ghi các bộ lọc hoạt động kém.
bernie

@bernie Bạn có thể làm rõ những gì cần thiết để trình đổ bóng tính toán được "thực hiện đúng" không? Có lẽ viết một câu trả lời? Luôn luôn tốt để có được nhiều quan điểm về chủ đề này. :)
Nathan Reed

2
Bây giờ hãy nhìn vào những gì bạn làm cho tôi làm! :)
bernie

Ngoài việc chia sẻ công việc giữa các luồng, khả năng sử dụng tính toán async là một lý do lớn để sử dụng trình đổ bóng tính toán.
JarkkoL

Câu trả lời:


23

Một lợi thế về kiến trúc của các shader tính toán để xử lý ảnh là chúng bỏ qua bước ROP . Rất có khả năng ghi từ trình đổ bóng pixel đi qua tất cả các phần cứng trộn thông thường ngay cả khi bạn không sử dụng nó. Nói chung, các shader tính toán đi qua một con đường khác (và thường trực tiếp hơn) vào bộ nhớ, vì vậy bạn có thể tránh được một nút cổ chai mà nếu không bạn sẽ có. Tôi đã nghe nói về chiến thắng hiệu suất khá lớn được quy cho điều này.

Một nhược điểm về kiến trúc của các shader tính toán là GPU không còn biết các mục công việc nào sẽ chuyển sang pixel nào. Nếu bạn đang sử dụng đường dẫn đổ bóng pixel, GPU có cơ hội đóng gói công việc vào một sợi dọc / mặt sóng ghi vào một khu vực của mục tiêu kết xuất tiếp giáp trong bộ nhớ (có thể được xếp theo thứ tự Z hoặc tương tự như vậy để thực hiện lý do). Nếu bạn đang sử dụng đường ống tính toán, GPU có thể không còn hoạt động theo lô tối ưu, dẫn đến sử dụng nhiều băng thông hơn.

Tuy nhiên, bạn có thể biến việc đóng gói warp / wavefront bị thay đổi thành lợi thế một lần nữa, nếu bạn biết rằng hoạt động cụ thể của bạn có một cấu trúc mà bạn có thể khai thác bằng cách đóng gói công việc liên quan vào cùng một nhóm luồng. Giống như bạn đã nói, về lý thuyết, bạn có thể cho phần cứng lấy mẫu tạm dừng bằng cách lấy mẫu một giá trị trên mỗi làn và đưa kết quả vào bộ nhớ dùng chung cho các làn khác để truy cập mà không cần lấy mẫu. Đây có phải là một chiến thắng hay không phụ thuộc vào mức độ bộ nhớ chia sẻ nhóm của bạn đắt đỏ: nếu nó rẻ hơn bộ đệm kết cấu cấp thấp nhất, thì đây có thể là một chiến thắng, nhưng không có gì đảm bảo điều đó. GPU đã xử lý khá tốt với các tìm nạp kết cấu cục bộ cao (do sự cần thiết).

Nếu bạn có một giai đoạn trung gian trong hoạt động mà bạn muốn chia sẻ kết quả, có thể có ý nghĩa hơn khi sử dụng bộ nhớ chia sẻ nhóm (vì bạn không thể quay lại phần cứng lấy mẫu kết cấu mà không thực sự ghi kết quả trung gian vào bộ nhớ). Thật không may, bạn cũng không thể phụ thuộc vào việc có kết quả từ bất kỳ nhóm luồng nào khác, vì vậy giai đoạn thứ hai sẽ phải tự giới hạn chỉ những gì có sẵn trong cùng một ô. Tôi nghĩ rằng ví dụ kinh điển ở đây là tính toán độ chói trung bình của màn hình để tự động phơi sáng. Tôi cũng có thể tưởng tượng việc kết hợp việc lấy mẫu kết cấu với một số thao tác khác (kể từ khi lấy mẫu, không giống như lấy mẫu và làm mờ, không phụ thuộc vào bất kỳ giá trị nào bên ngoài một ô cụ thể).


Tôi thực sự nghi ngờ ROP sẽ thêm bất kỳ chi phí hiệu năng nào nếu việc trộn bị vô hiệu hóa.
GroverManheim

@GroverManheim Phụ thuộc vào kiến ​​trúc! Bước sáp nhập đầu ra / ROP cũng phải xử lý các đảm bảo đặt hàng ngay cả khi pha trộn bị vô hiệu hóa. Với hình tam giác toàn màn hình, không có bất kỳ rủi ro đặt hàng thực tế nào, nhưng phần cứng có thể không biết điều đó. Có thể có những đường dẫn nhanh đặc biệt trong phần cứng, nhưng biết chắc chắn rằng bạn đủ điều kiện cho chúng
LỚN

10

John đã viết một câu trả lời tuyệt vời vì vậy hãy xem câu trả lời này là một phần mở rộng của mình.

Tôi hiện đang làm việc rất nhiều với các shader tính toán cho các thuật toán khác nhau. Nói chung, tôi đã thấy rằng các trình đổ bóng tính toán có thể nhanh hơn nhiều so với trình đổ bóng pixel tương đương của chúng hoặc chuyển đổi các lựa chọn thay thế dựa trên phản hồi.

Một khi bạn quấn đầu xung quanh cách các shader tính toán hoạt động, chúng cũng có ý nghĩa hơn rất nhiều trong nhiều trường hợp. Sử dụng các pixel shader để lọc một hình ảnh đòi hỏi phải thiết lập bộ đệm khung, gửi các đỉnh, sử dụng nhiều giai đoạn đổ bóng, v.v ... Tại sao điều này cần phải có để lọc một hình ảnh? Theo tôi, được sử dụng để hiển thị các quads toàn màn hình để xử lý hình ảnh là lý do "hợp lệ" duy nhất để tiếp tục sử dụng chúng theo ý kiến ​​của tôi. Tôi tin rằng một người mới đến với lĩnh vực đồ họa tính toán sẽ tìm thấy các trình đổ bóng tính toán phù hợp tự nhiên hơn nhiều để xử lý hình ảnh so với kết xuất thành họa tiết.

Câu hỏi của bạn đề cập đến việc lọc hình ảnh nói riêng vì vậy tôi sẽ không giải thích quá nhiều về các chủ đề khác. Trong một số thử nghiệm của chúng tôi, chỉ cần thiết lập phản hồi chuyển đổi hoặc chuyển đổi các đối tượng bộ đệm khung để kết xuất thành kết cấu có thể phải chịu chi phí hiệu suất khoảng 0,2ms. Hãy nhớ rằng điều này không bao gồm bất kỳ kết xuất! Trong một trường hợp, chúng tôi đã giữ chính xác thuật toán được chuyển để tính toán các shader và thấy hiệu suất tăng đáng chú ý.

Khi sử dụng các shader tính toán, nhiều silicon trên GPU có thể được sử dụng để thực hiện công việc thực tế. Tất cả các bước bổ sung này là bắt buộc khi sử dụng tuyến đổ bóng pixel:

  • Tập hợp Vertex (đọc các thuộc tính đỉnh, ước số đỉnh, chuyển đổi loại, mở rộng chúng thành vec4, v.v.)
  • Trình tạo bóng đỉnh cần được lên lịch cho dù nó tối thiểu đến mức nào
  • Trình rasterizer phải tính toán một danh sách các pixel để tô bóng và nội suy các đầu ra đỉnh (có lẽ chỉ là các kết cấu kết cấu để xử lý hình ảnh)
  • Tất cả các trạng thái khác nhau (kiểm tra độ sâu, kiểm tra alpha, cắt kéo, trộn) phải được thiết lập và quản lý

Bạn có thể lập luận rằng tất cả các lợi thế về hiệu suất được đề cập trước đây có thể bị phủ nhận bởi một trình điều khiển thông minh. Bạn sẽ đúng. Trình điều khiển như vậy có thể xác định rằng bạn đang hiển thị một quad toàn màn hình mà không cần kiểm tra độ sâu, v.v. và định cấu hình "đường dẫn nhanh" bỏ qua tất cả các công việc vô ích được thực hiện để hỗ trợ trình đổ bóng pixel. Tôi sẽ không ngạc nhiên nếu một số trình điều khiển làm điều này để tăng tốc các lượt xử lý hậu kỳ trong một số trò chơi AAA cho các GPU cụ thể của họ. Tất nhiên bạn có thể quên bất kỳ điều trị như vậy nếu bạn không làm việc trên một trò chơi AAA.

Tuy nhiên, những gì người lái xe không thể làm là tìm các cơ hội song song tốt hơn được cung cấp bởi đường ống đổ bóng tính toán. Lấy ví dụ cổ điển về bộ lọc gaussian. Sử dụng shader shute, bạn có thể làm một cái gì đó như thế này (tách bộ lọc hoặc không):

  1. Đối với mỗi nhóm công việc, hãy chia mẫu của hình ảnh nguồn theo kích thước nhóm công việc và lưu trữ kết quả vào bộ nhớ dùng chung của nhóm.
  2. Tính toán đầu ra của bộ lọc bằng các kết quả mẫu được lưu trong bộ nhớ dùng chung.
  3. Viết vào kết cấu đầu ra

Bước 1 là chìa khóa ở đây. Trong phiên bản đổ bóng pixel, hình ảnh nguồn được lấy mẫu nhiều lần trên mỗi pixel. Trong phiên bản shader tính toán, mỗi texel nguồn chỉ được đọc một lần trong một nhóm làm việc. Đọc kết cấu thường sử dụng bộ đệm dựa trên ô, nhưng bộ đệm này vẫn chậm hơn nhiều so với bộ nhớ dùng chung.

Bộ lọc gaussian là một trong những ví dụ đơn giản hơn. Các thuật toán lọc khác cung cấp các cơ hội khác để chia sẻ kết quả trung gian trong các nhóm làm việc bằng cách sử dụng bộ nhớ dùng chung.

Có đó, tuy nhiên, một nắm bắt. Tính toán shader yêu cầu các rào cản bộ nhớ rõ ràng để đồng bộ hóa đầu ra của chúng. Cũng có ít biện pháp bảo vệ hơn để bảo vệ chống lại truy cập bộ nhớ sai lầm. Đối với các lập trình viên có kiến ​​thức lập trình song song tốt, các shader tính toán cung cấp sự linh hoạt hơn nhiều. Tuy nhiên, tính linh hoạt này có nghĩa là cũng dễ dàng hơn để xử lý các shader tính toán như mã C ++ thông thường và viết mã chậm hoặc không chính xác.

Tài liệu tham khảo


Tính song song lấy mẫu được cải thiện mà bạn mô tả rất hấp dẫn - Tôi có một sim chất lỏng đã được triển khai với các shader tính toán với rất nhiều phiên bản của nhiều mẫu trên mỗi pixel .. Sử dụng bộ nhớ chia sẻ nhóm để lấy mẫu đơn lẻ với hàng rào bộ nhớ như bạn mô tả có vẻ rất tuyệt, nhưng tôi gác máy một chút - làm cách nào để truy cập các pixel lân cận khi chúng rơi vào một nhóm công việc khác? ví dụ: nếu tôi có miền mô phỏng 64x64, trải đều trên một công văn (2,2,1) chữ số (16,16,1), làm thế nào pixel với id.xy == [15,15] có được các pixel lân cận ?
Tossrock

Trong trường hợp đó, tôi thấy 2 lựa chọn chính. 1) tăng kích thước nhóm trên 64 và chỉ ghi kết quả cho 64x64 pixel. 2) mẫu đầu tiên 64 + nX64 + n được chia theo cách nào đó trong nhóm công việc 64x64 của bạn và sau đó sử dụng lưới "đầu vào" lớn hơn đó cho các tính toán. Giải pháp tốt nhất phụ thuộc vào điều kiện cụ thể của bạn và tôi khuyên bạn nên viết lên một câu hỏi khác để biết thêm thông tin vì các bình luận không phù hợp cho việc này.
bernie

3

Tôi tình cờ thấy trên blog này: Tính toán tối ưu hóa Shader cho AMD

Dựa vào những thủ thuật nào có thể được thực hiện trong shader tính toán (chỉ dành riêng cho tính toán shader) Tôi tò mò liệu việc giảm song song trên shader tính toán có nhanh hơn so với shader pixel hay không. Tôi đã gửi e-mail cho tác giả, Wolf Engel, để hỏi liệu anh ta đã thử dùng pixel shader chưa. Anh ta trả lời là có và quay lại khi anh ta viết bài đăng trên blog, phiên bản shader tính toán nhanh hơn đáng kể so với phiên bản shader pixel. Ông cũng nói thêm rằng ngày nay sự khác biệt thậm chí còn lớn hơn. Vì vậy, rõ ràng có những trường hợp sử dụng shader tính toán có thể có lợi thế lớn.

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.