Tại sao an toàn luồng lại là một vấn đề lớn như vậy đối với API đồ họa?


21

Cả Vulkan và DirectX12 đều được tuyên bố là có thể sử dụng theo cách an toàn cho chuỗi. Mọi người dường như rất hào hứng về điều đó.

Tại sao điều này được coi là một tính năng rất lớn? Việc xử lý "thực" được ném qua cầu bộ nhớ trên một đơn vị xử lý riêng biệt.

Ngoài ra, nếu nó quá lớn, tại sao đến bây giờ, API đồ họa an toàn của luồng lại xuất hiện?


Bài viết này "tập trung nhiều game thủ" hơn nhưng nó có thể cung cấp cho bạn một số thông tin chi tiết ... pcgamer.com/what-directx-12-means-for-gamers-and-developers
glampert

Câu trả lời:


13

Lợi ích chính là việc phân chia các tác vụ CPU thành nhiều luồng sẽ dễ dàng hơn mà không phải giải quyết tất cả các vấn đề khó khăn khi truy cập API đồ họa. Thông thường, bạn sẽ phải tạo bối cảnh hiện tại (có thể có ý nghĩa hiệu suất kém) hoặc cung cấp một hàng đợi và gọi api đồ họa trong một luồng. Tôi không nghĩ rằng bất kỳ hiệu suất nào cũng đạt được theo cách này, vì GPU thực sự xử lý chúng theo tuần tự, nhưng nó giúp công việc của nhà phát triển dễ dàng hơn rất nhiều.

Lý do mà nó không được thực hiện cho đến bây giờ có lẽ là vì directx và opengl đã được tạo ra trong thời điểm mà đa luồng không thực sự rõ ràng. Ngoài ra, ban Khronos rất thận trọng trong việc thay đổi API. Quan điểm của họ về Vulkan cũng là nó sẽ cùng tồn tại bên cạnh OpenGL, vì cả hai đều phục vụ các mục đích khác nhau. Có lẽ cho đến gần đây, sự tê liệt trở nên rất quan trọng, khi người tiêu dùng tiếp cận với ngày càng nhiều bộ xử lý.

EDIT: Tôi không có nghĩa là không có hiệu suất nào đạt được khi thực hiện công việc trong nhiều CPU, việc chia các cuộc gọi của bạn thành nhiều luồng để tạo kết cấu / đổ bóng nhanh hơn là không hữu ích. Thay vào đó, hiệu suất đạt được do có nhiều bộ xử lý bận hơn và khiến gpu bận rộn với những thứ cần thực hiện.


1
Như một lưu ý thêm, OpenGL thường chỉ hoạt động trên một luồng nên ứng dụng chuyên sâu về đồ họa có thể tối đa hóa một lõi. Một cái gì đó như Vulkan cho phép nhiều luồng gửi lệnh đến hàng đợi, điều đó có nghĩa là nhiều lệnh gọi đồ họa có thể được thực hiện từ nhiều luồng.
Xà phòng

9

Có rất nhiều công việc cần thiết trên CPU để thiết lập khung cho GPU và một phần tốt của công việc đó nằm trong trình điều khiển đồ họa. Trước DX12 / Vulkan, công việc trình điều khiển đồ họa về cơ bản buộc phải được xử lý đơn luồng theo thiết kế của API.

Hy vọng là DX12 / Vulkan nâng hạn chế đó, cho phép trình điều khiển hoạt động được thực hiện song song trên nhiều luồng CPU trong một khung. Điều này sẽ cho phép sử dụng CPU đa lõi hiệu quả hơn, cho phép các công cụ trò chơi đẩy các cảnh phức tạp hơn mà không bị ràng buộc CPU. Đó là hy vọng, liệu điều đó có thành hiện thực trong thực tế hay không là điều chúng ta sẽ phải chờ đợi trong vài năm tới.

Để giải thích một chút: đầu ra của trình kết xuất công cụ trò chơi là một luồng các lệnh gọi API DX / GL mô tả chuỗi các thao tác để kết xuất khung. Tuy nhiên, có một khoảng cách lớn giữa luồng lệnh gọi API và bộ đệm lệnh nhị phân thực tế mà phần cứng GPU tiêu thụ. Trình điều khiển phải "biên dịch" các lệnh gọi API sang ngôn ngữ máy của GPU. Đó không phải là một quá trình tầm thường, nó bao gồm rất nhiều bản dịch các khái niệm API sang thực tế phần cứng cấp thấp, xác thực để đảm bảo GPU không bao giờ được đặt ở trạng thái không hợp lệ, phân bổ bộ nhớ và dữ liệu, theo dõi các thay đổi trạng thái để phát hành sửa các lệnh cấp thấp, v.v. Trình điều khiển đồ họa chịu trách nhiệm cho tất cả những thứ này.

Trong DX11 / GL4 và các API trước đó, công việc này thường được thực hiện bởi một luồng trình điều khiển duy nhất. Ngay cả khi bạn gọi API từ nhiều luồng (mà bạn có thể thực hiện bằng cách sử dụng danh sách lệnh trì hoãn DX11 chẳng hạn), nó chỉ thêm một số công việc vào hàng đợi cho luồng trình điều khiển để nhai lại sau. Một lý do lớn cho việc này là theo dõi trạng thái tôi đã đề cập trước đó. Nhiều chi tiết cấu hình GPU cấp phần cứng yêu cầu kiến ​​thức về trạng thái đường ống đồ họa hiện tại, vì vậy không có cách nào tốt để chia danh sách lệnh thành các khối có thể được xử lý song song, mỗi đoạn sẽ phải biết chính xác trạng thái nào sẽ bắt đầu với, mặc dù đoạn trước chưa được xử lý.

Đó là một trong những điều lớn đã thay đổi trong DX12 / Vulkan. Đối với một điều, chúng kết hợp gần như tất cả trạng thái đường ống đồ họa vào một đối tượng và đối với một đối tượng khác (ít nhất là trong DX12) khi bạn bắt đầu tạo danh sách lệnh, bạn phải cung cấp trạng thái đường ống ban đầu; trạng thái không được kế thừa từ danh sách lệnh này sang danh sách tiếp theo. Về nguyên tắc, điều này cho phép người lái không phải biết bất cứ điều gì về danh sách lệnh trước đó trước khi có thể bắt đầu biên dịch mã hóa và điều đó cho phép ứng dụng chia nhỏ kết xuất của nó thành các đoạn song song, tạo ra danh sách lệnh được biên dịch đầy đủ, sau đó có thể nối với nhau và gửi đến GPU với mức tối thiểu phiền phức.

Tất nhiên, có nhiều thay đổi khác trong các API mới, nhưng theo như đa luồng, đó là phần quan trọng nhất.


5

Các GPU hiện đại thường có một phần lối vào duy nhất xử lý một dòng lệnh hoàn toàn tuyến tính từ CPU. Cho dù đây là một thiết kế phần cứng tự nhiên hay chỉ đơn giản là nó đã phát triển ra khỏi thời mà có một lệnh tạo lõi CPU duy nhất cho GPU vẫn còn gây tranh cãi, nhưng đó là thực tế cho đến bây giờ. Vì vậy, nếu bạn tạo một luồng tuyến tính của các lệnh trạng thái, tất nhiên sẽ có ý nghĩa khi tạo luồng đó tuyến tính trên một luồng trên CPU! Đúng?

Chà, GPU hiện đại nói chung cũng có một phụ trợ hợp nhất rất linh hoạt có thể hoạt động trên nhiều thứ khác nhau cùng một lúc. Nói chung, GPU hoạt động trên các đỉnh và pixel ở độ chi tiết khá tốt. Không có nhiều sự khác biệt giữa GPU xử lý 1024 đỉnh trong một lần vẽ và 512 + 512 đỉnh trong hai lần rút khác nhau.

Điều đó cho thấy một cách khá tự nhiên để thực hiện ít công việc hơn: thay vì ném một số lượng lớn các đỉnh vào GPU trong một cuộc gọi rút thăm duy nhất, chia mô hình của bạn thành các phần, thực hiện loại bỏ giá rẻ trên các phần đó và gửi từng phần riêng lẻ nếu nó vượt qua kiểm tra loại thải. Nếu bạn làm điều đó ở mức độ chi tiết phù hợp, bạn sẽ có được một tốc độ tốt đẹp!

Thật không may, trong thực tế API đồ họa hiện tại, các lệnh gọi rút tiền cực kỳ tốn kém trên CPU. Một lời giải thích đơn giản về lý do: các thay đổi trạng thái trên GPU có thể không tương ứng trực tiếp với các lệnh gọi API đồ họa, vì vậy nhiều lệnh gọi API đồ họa chỉ đơn giản đặt một số trạng thái bên trong trình điều khiển và lệnh gọi phụ thuộc vào trạng thái mới này và xem xét tất cả trạng thái được đánh dấu là đã thay đổi kể từ lần rút cuối cùng, ghi nó vào luồng lệnh cho GPU, sau đó thực sự bắt đầu rút thăm. Đây là tất cả các công việc được thực hiện trong nỗ lực để có được một luồng lệnh nạc và trung bình cho đơn vị giao diện GPU.

Điều này có nghĩa là bạn có ngân sách dành cho các cuộc gọi rút thăm hoàn toàn do chi phí của người lái xe . (Tôi nghĩ rằng tôi đã nghe nói rằng những ngày này bạn có thể thoát khỏi khoảng 5.000 mỗi khung hình cho một tiêu đề 60 FPS.) Bạn có thể tăng tỷ lệ đó bằng một tỷ lệ lớn bằng cách xây dựng luồng lệnh này thành các khối song song.

Cũng có những lý do khác (ví dụ, thời gian không đồng bộ để cải thiện độ trễ VR), nhưng đây là một lý do lớn cho các trò chơi giới hạn đồ họa và phần mềm nặng khác (như gói mô hình 3D).

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.