Thông tin về kết xuất, lô, card đồ họa, hiệu suất, vv + XNA?


12

Tôi biết tiêu đề hơi mơ hồ nhưng thật khó để mô tả những gì tôi thực sự tìm kiếm, nhưng ở đây đi.

Khi nói đến kết xuất CPU, hiệu năng hầu như dễ ước tính và đơn giản, nhưng khi nói đến GPU do thiếu thông tin cơ bản về kỹ thuật, tôi không biết gì. Tôi đang sử dụng XNA nên thật tuyệt nếu lý thuyết có thể liên quan đến điều đó.

Vì vậy, những gì tôi thực sự muốn biết là, điều gì xảy ra khi nào và ở đâu (CPU / GPU) khi bạn thực hiện các hành động vẽ cụ thể? Một lô là gì? Những ảnh hưởng nào ảnh hưởng, dự đoán vv có? Là dữ liệu tồn tại trên card đồ họa hay nó được chuyển qua từng bước? Khi nói về băng thông, bạn đang nói về băng thông bên trong của card đồ họa hay đường ống từ CPU đến GPU?
Lưu ý: Tôi thực sự không tìm kiếm thông tin về quá trình vẽ diễn ra như thế nào , đó là công việc của GPU, tôi quan tâm đến tất cả các chi phí trước đó.

Tôi muốn hiểu những gì đang xảy ra khi tôi thực hiện hành động X, để điều chỉnh kiến ​​trúc và thực tiễn của tôi với điều đó.

Bất kỳ bài viết nào (có thể có ví dụ về mã), thông tin, liên kết, hướng dẫn cung cấp cái nhìn sâu sắc hơn về cách viết trò chơi tốt hơn đều được đánh giá cao. Cảm ơn :)


2
Mặc dù ban đầu đây là XNA, tôi đã thêm thẻ DirectX, vì đó là công nghệ cơ bản - nó có thể giúp bạn có câu trả lời tốt hơn. Ngoài ra kiểm tra câu trả lời này có thể cung cấp cho bạn một điểm khởi đầu tốt.
Andrew Russell

@AndrewRussell Cảm ơn rất nhiều :). Tôi thực sự đã đọc các bài viết khác nhau về chủ đề bao gồm cả bài viết đó. Nhưng nó không bao gồm mọi thứ tôi muốn biết.
Aidiakapi

Câu trả lời:


20

Tôi thích nghĩ về hiệu suất theo " giới hạn ". Đó là một cách thuận tiện để khái niệm một hệ thống kết nối khá phức tạp. Khi bạn gặp vấn đề về hiệu suất, bạn đặt câu hỏi: "Tôi đang đạt đến giới hạn nào?" (Hoặc: "Tôi có bị ràng buộc CPU / GPU không?")

Bạn có thể chia nó thành nhiều cấp độ. Ở cấp độ cao nhất, bạn có CPU và GPU. Bạn có thể bị ràng buộc CPU (GPU ngồi chờ CPU) hoặc ràng buộc GPU (CPU đang chờ GPU). Đây là một bài viết blog tốt về chủ đề này.

Bạn có thể phá vỡ nó hơn nữa. Về phía CPU , bạn có thể đang sử dụng tất cả các chu kỳ của mình trên dữ liệu đã có trong bộ đệm CPU. Hoặc bạn có thể bị giới hạn bộ nhớ , khiến CPU không hoạt động khi chờ dữ liệu đến từ bộ nhớ chính ( để tối ưu hóa bố cục dữ liệu của bạn ). Bạn có thể phá vỡ nó hơn nữa vẫn còn.

(Trong khi tôi đang thực hiện tổng quan rộng về hiệu suất liên quan đến XNA, tôi sẽ chỉ ra rằng việc phân bổ loại tham chiếu ( classkhông struct), trong khi giá rẻ, có thể kích hoạt trình thu gom rác, sẽ đốt cháy rất nhiều chu kỳ - đặc biệt là trên Xbox 360 . Xem ở đây để biết chi tiết).

Về phía GPU , tôi sẽ bắt đầu bằng cách chỉ cho bạn bài đăng blog tuyệt vời này có rất nhiều chi tiết. Nếu bạn muốn một mức độ chi tiết điên rồ trên đường ống, hãy đọc loạt bài viết trên blog này . ( Đây là một đơn giản hơn ).

Nói một cách đơn giản, một số trong những cái lớn là: " giới hạn lấp đầy " (bạn có thể ghi bao nhiêu pixel vào backbuffer - thường là bạn có thể rút bao nhiêu tiền), " giới hạn shader " (mức độ shader của bạn có thể phức tạp đến mức nào) bạn có thể đẩy bao nhiêu dữ liệu qua chúng), " giới hạn kết cấu tìm nạp / kết cấu băng thông " (bao nhiêu dữ liệu kết cấu bạn có thể truy cập).

Và bây giờ, chúng ta đến với vấn đề lớn - đó là những gì bạn thực sự yêu cầu - nơi CPU và GPU phải tương tác (thông qua các trình điều khiển và API khác nhau). Một cách lỏng lẻo là " giới hạn lô " và " băng thông ". (Lưu ý rằng phần một của loạt tôi đã đề cập trước đó đi vào sâu rộng thêm chi tiết.)

Nhưng, về cơ bản, một ( như bạn đã biết ) xảy ra bất cứ khi nào bạn gọi một trong các GraphicsDevice.Draw*hàm (hoặc một phần của XNA, như SpriteBatch, điều này sẽ giúp bạn). Vì bạn chắc chắn đã đọc, bạn nhận được vài nghìn * trong số này trên mỗi khung. Đây là giới hạn CPU - vì vậy nó cạnh tranh với việc sử dụng CPU khác của bạn. Về cơ bản, trình điều khiển đóng gói mọi thứ về những gì bạn đã bảo nó vẽ và gửi nó tới GPU.

Và sau đó là băng thông cho GPU. Đây là bao nhiêu dữ liệu thô bạn có thể chuyển ở đó. Điều này bao gồm tất cả các thông tin trạng thái đi kèm theo lô - mọi thứ từ cài đặt trạng thái kết xuất và các tham số / tham số đổ bóng (bao gồm những thứ như ma trận thế giới / khung nhìn / dự án), cho đến các đỉnh khi sử dụng các DrawUser*hàm. Nó cũng bao gồm bất kỳ cuộc gọi đến SetDataGetDatatrên kết cấu, bộ đệm đỉnh, v.v.

Tại thời điểm này tôi nên nói rằng bất cứ điều gì bạn có thể gọi SetData(kết cấu, bộ đệm đỉnh và chỉ mục, v.v.), cũng như Effects - vẫn còn trong bộ nhớ GPU. Nó không liên tục được gửi lại cho GPU. Lệnh draw tham chiếu dữ liệu đó được gửi đơn giản bằng một con trỏ tới dữ liệu đó.

(Ngoài ra: bạn chỉ có thể gửi lệnh vẽ từ luồng chính, nhưng bạn có thể SetDatatrên bất kỳ luồng nào.)

XNA làm phức tạp mọi thứ hơi với khiến lớp trạng thái của nó ( BlendState, DepthStencilState, vv). Dữ liệu trạng thái này được gửi cho mỗi cuộc gọi bốc thăm (trong mỗi đợt). Tôi không chắc chắn 100%, nhưng tôi có ấn tượng rằng nó được gửi một cách lười biếng (nó chỉ gửi trạng thái thay đổi). Dù bằng cách nào, thay đổi trạng thái là rẻ đến mức miễn phí, liên quan đến chi phí của một đợt.

Cuối cùng, điều cuối cùng cần đề cập là đường ống GPU bên trong . Bạn không muốn buộc nó phải xóa bằng cách ghi vào dữ liệu mà nó vẫn cần đọc hoặc đọc dữ liệu mà nó vẫn cần ghi. Một đường ống xả có nghĩa là nó chờ các hoạt động kết thúc, để mọi thứ ở trạng thái nhất quán khi dữ liệu được truy cập.

Hai trường hợp cụ thể cần chú ý là: Gọi GetDatabất cứ thứ gì động - đặc biệt là RenderTarget2DGPU có thể được ghi vào. Điều này cực kỳ tệ cho hiệu suất - đừng làm điều đó.

Trường hợp khác là gọi SetDatabộ đệm đỉnh / chỉ mục. Nếu bạn cần làm điều này thường xuyên, sử dụng một DynamicVertexBuffer(cũng DynamicIndexBuffer). Điều này cho phép GPU biết rằng chúng sẽ thay đổi thường xuyên và thực hiện một số phép thuật đệm trong nội bộ để tránh hiện tượng lộn đường ống.

(Cũng lưu ý rằng bộ đệm động nhanh hơn DrawUser*các phương thức - nhưng chúng phải được phân bổ trước ở kích thước tối đa được yêu cầu.)

... Và đó là tất cả mọi thứ tôi biết về hiệu suất XNA :)


Cảm ơn bạn rất nhiều! Đây chính xác là những gì tôi đang tìm kiếm và hy vọng :).
Aidiakapi

1
Vài trăm lô trên mỗi khung nghe có vẻ quá bi quan. Quy tắc ngón tay cái mà tôi luôn nghe thấy là 2K đến 3K lô mỗi khung. Một số trò chơi đã được biết là có thể lên tới 10 nghìn trên PC, nhưng tôi nghĩ rằng điều đó đòi hỏi sự chăm sóc tuyệt vời để đạt được.
Nathan Reed

Khá đúng. Con số "vài trăm" xuất phát từ bài báo "lô lô" - liệt kê "lô 25k / s @ 100% CPU 1GHz". Nhưng bài báo đó đã được một thập kỷ và trình điều khiển và CPU đã được cải thiện đáng kể kể từ đó. Tôi sẽ cập nhật cái này (và những cái khác của tôi) để đọc "vài nghìn".
Andrew Russell
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.